Flutter apps and web adaptive UI layout - flutter

I have been working on flutter mobile apps, already released multiple version to AppStore/PlayStore.
The code is built for mobile app design.
I am currently looking to support website using the same codebase.
One of the issue with supporting both mobile apps and web is that the UI layout is different.
For example: We will have top bar actions in web but bottom bar navigation in mobile apps.
I think I can use kIsWeb like below to create different appBar and bottomNavigationBar
for each Scaffold widget in each screen.
if (kIsWeb){
\\ web code
}
else{
\\ app code
}
What is the best strategy to build adaptive UI which works for mobile apps and website using same codebase?

Modify this according to your use case :)
1.) Define constraints
const mobileWidth = 480;
const tabletWidth = 900;
const desktopWidth = 1180;
2.) Create a Responsive widget which change layout according to screen size
class ResponsiveLayout extends StatelessWidget {
const ResponsiveLayout({
Key? key,
this.mobileView,
this.tabletView,
this.desktopView,
}) : super(key: key);
final Widget? mobileView;
final Widget? tabletView;
final Widget? desktopView;
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, dimens) {
if (dimens.maxWidth <= tabletWidth) {
if (dimens.maxWidth <= mobileWidth) {
return mobileView ?? Text("Mobile view");
} else {
return tabletView ?? Text("Tablet view");
}
} else {
return desktopView ?? Text("Desktop view");
}
});
}
}
3.) Use this responsive widget where you want
class CourseScreen extends StatelessWidget {
const CourseScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const ResponsiveLayout(
mobileView: CourseMobileScreen(),
tabletView: CourseTabletScreen(),
desktopView: CourseDesktopScreen(),
);
}
}

Most likely UI depends on screen size rather than it is running on web or not. The web page can be resized and needed to maintain UI. Mostly I prefer using LayoutBuilder for responsiveness. You can also find some good package on pub. While there are some different functionality/feature depends on between os app/ web app, in this case I use kIsWeb. A web app can be used by android browser.
You can check more about adaptive-responsive design.

You should try responsive_framework pkg. I have used it in my Single code base and created different screen resolution breakpoints as per my use cases.
For ex.
builder: (context, widget) => ResponsiveWrapper.builder(
BouncingScrollWrapper.builder(context, widget),
maxWidth: MediaQuery.of(context).size.width/3,
minWidth: 450,
defaultScale: true,
breakpoints: [
ResponsiveBreakpoint.resize(450, name: MOBILE),
ResponsiveBreakpoint.autoScale(800, name: TABLET),
ResponsiveBreakpoint.autoScale(1000, name: TABLET),
ResponsiveBreakpoint.resize(1200, name: DESKTOP),
ResponsiveBreakpoint.autoScale(2460, name: "4K"),
],
background: Container(color: Color(0xFFF5F5F5))
),
Accordingly, use breakpoints for your UI.
Or
You can create your own screen configs using MediaQuery in a separate file e.g., SizeConfig
For ex.
For Mobile > max_width x maxheight can be 300 x 480. likewise for Tablet and Desktop.
Then you can use it to inflate list items in GridView (for crossAxisCount) and ListView items

Related

Flutter CircularProgressIndicator Freeze When Navigate to Another Page for a millisecond

iam new at flutter iam trying to add CircularProgressIndicator at page loading and then change state but its seems like it freeze on navigation
Main.Dart
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: AppString.appName,
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: Colors.grey.shade900,
),
home: const DummyScreen(),
);
}
}
Navigation Screen
class DummyScreen extends StatelessWidget {
const DummyScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
child: const Text("Navigate"),
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AnotherDummyScreen()));
},
),
),
);
}
}
CircularProgressIndicator Screen
class AnotherDummyScreen extends StatelessWidget {
const AnotherDummyScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
CircularProgressIndicator Widget Should be more smoothly at page Load as it take a while to start animate
I assume you run this on an emulator or are performing any other heavy performance tasks either in your app or on the device?
Why you have to test on real device taken from the flutter docs:
Simulators and emulators don’t use the same hardware, so their performance characteristics are different some operations are faster on simulators than real devices, and some are slower.
Debug mode enables additional checks (such as asserts) that don’t run in profile or release builds, and these checks can be expensive.
Debug mode also executes code in a different way than release mode. The debug build compiles the Dart code “just in time” (JIT) as the app runs, but profile and release builds are pre-compiled to native instructions (also called “ahead of time”, or AOT) before the app is loaded onto the device. JIT can cause the app to pause for JIT compilation, which itself can cause jank.
"Jank" can have multiple reasons. The you provided code looks totally fine.
If you are running this on a real device I recommened to take look at concrete profiling in flutter. You can do for instance:
flutter run --profile
Note that you also should do profiling always on a real device.
With profiling you can then identify the root issue of your jittering animation. The link from the flutter docs above also does provide a good understanding on how profiling works and how to interpret everything. It also provides information on how to use the flutter dev tools, VScode and Android Studio for further performance analysis.
Rebuild app and try or try on other device.

Animated screen between a navigation of two screens in flutter

I have three screens.
FirstScreen, SecondScreen and a GreenScreen,
im using custom navigation in my navigation routes like so (im using named routes),
case secondScreenUIRoute:
return Platform.isIOS
? CupertinoPageRoute(
builder: (context) => const SecondScreen())
: CustomPageRoute(
builder: (context) => const SecondScreen());
my green screen looks like so
class GreenScreen extends StatelessWidget {
const GreenScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: CustomColors.greenLight,
);
}
}
My basic idea was to have this GreenScreen in between FirstScreen and SecondScreen on navigation(from first to second), but as a fade in fade out effect. Plainly I like to give the user an impression like, when going from FirstScreen to SecondScreen, there seems to be a subtle animation where a green screen is faded in and faded out before reaching SecondScreen.
how Can i achieve this in flutter?
you can use animations package:
https://pub.dev/packages/animations#fade-through
This package contains pre-canned animations for commonly-desired effects. The animations can be customized with your content and dropped into your application to delight your users.
this is an example source code of using the package:
https://github.com/flutter/packages/tree/master/packages/animations/example
if you want to learn from youtube, you can learn here:
https://www.youtube.com/watch?v=3GMq45zRVLo
I've used this package before, and I recommend this package because it's easy to use and this package was made by the flutter team

WebView on Flutter Web Not working with external library

currently I am developing an app using Flutter Web and I've been trying to use this library which does not have a lot of documentation.
I've tried the example provided but for some reason it's not working
In the example there is no onLoaded() {} function method and without that I get an error saying that I have to implement it.
Finally, if I want to set the width and height of the website I should call setState(). How do I do that?
Link to the library https://pub.dev/packages/easy_web_view2
Code: (I'm running main() in another file)
import 'package:flutter/material.dart';
import 'package:easy_web_view2/easy_web_view2.dart';
class Quiz extends StatelessWidget {
const Quiz({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('CyberQuiz'),
),
body: EasyWebView(
src: 'https://www.ncsc.gov.uk/',
onLoaded: () {
print('Loaded!!');
},
),
);
}
}
A bit of an unobvious issue. I was trying to embed a government website. Apparently you are not allowed to do that.
I am also using a different library which is called webviewx. It has better documentation than the other one

How can I make a SliverAppBar that is similar to Google News?

I want a standard AppBar when the app starts, however, once the user begins scrolling I want the app bar to slide up and off the screen. However, when that happens, the status bar (on iOS) doesn't have a background. I don't want to set a constant background directly to the status bar using something like flutter_statusbarcolor because that leaves a solid color, which isn't a widget.
The only solution I have right now is to just keep the AppBar pined.
However, what I really want to do is what Google News does. The AppBar slides up almost all the way, however, it stays under the app bar with some opacity.
How Google News does it:
Is there any way to do this with Flutter and SliverAppBar without doing it a hacky way? The only thing I'm thinking is doing it with a stack, however, how would I know how to keep it under the status bar, as Android already has some opacity under the status bar.
Scroll widgets in flutter have controllers that inform what's going on with the scroll. You can get how much the sliver has been scrolled and change it's opacity, content and size accordingly. It's not going to be simple though, but take a look at ScrollController, used by the CustomScrollView.
I used OrientationBuilder widget to listen to changes in orientation, as when there are changes to the orientation the status bar hight can change.
Then I used FlutterStatusbarManager package to get the height of the status bar. FlutterStatusbarManager.getHeight is a future so it needed to be wrapped with a FutureBuilder
Here is the full example code
import 'package:flutter/material.dart';
import 'package:flutter_statusbar_manager/flutter_statusbar_manager.dart';
class FixedStatusbarBackground extends StatelessWidget {
final Widget child;
const FixedStatusbarBackground({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
child,
OrientationBuilder(
builder: (context, Orientation orientation) => FutureBuilder<double>(
future: FlutterStatusbarManager.getHeight,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
height: snapshot.data,
color: Theme.of(context)
.appBarTheme
.color
.withOpacity(.7) //Colors.white.withOpacity(.7),
);
} else {
return Container();
}
}),
),
],
);
}
}
The child widget that is passed in is the entire CustomScrollView.

Flutter: Is it possible to auto-scale (whole) ui based on device size?

iOS native apps auto-scale the whole ui based on device size (width). Is there a similar behaviour with flutter?
I want to design a ui (with font sizes, paddings, etc) for a master device (iphone xs) and scale the whole ui to all other devices.
Wondering if that is possible as i couldn't find any information about it.
Just responsive sizing that needs me to configure breakpoints etc.
I usually obtain device size on Widget build, and then use a fraction of the width and height for each widget: Something like this:
import 'package:flutter/material.dart';
Size deviceSize;
class Welcome extends StatefulWidget {
WelcomeState createState() => WelcomeState();
}
class WelcomeState extends State<Welcome> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
deviceSize = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: color3,
body: Container(
height:deviceSize.height*0.5,
width:deviceSize.width-50.0,
child: Text("Welcome"),
),
);
}
}
Yes, this indeed is possible. All you need is a ratio-scaling approach with which you scale your entire GUI. Check out this ratio-scaling solution given to another SO answer relating to the Flutter UI scaling issue.
It's better to use MediaQuery.of(context).size, because while using external package, you won't be able to maintain the size of widgets on orientation change which might be a big downfall if your application required orientation change for better visual effects:
Widget build(BuildContext context) {
AppBar appBar = AppBar(title: const Text("My Dashboard"));
height = MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top; // for responsive adjustment
width = MediaQuery.of(context).size.width; // for responsive adjustment
debugPrint("$height, width: ${MediaQuery.of(context).size.width}");
return Scaffold(appBar: appBar, body: ResponsivePage(height,width));
}
Check out this package:
https://pub.dev/packages/scaled_app
Replace runApp with runAppScaled, the entire UI design will be scaled automatically.
Helpful when you want adapt to different screen sizes quickly