Flutter is a cross platform application development framework that supports devices with large screen size changes: it can run on devices as small as smart watches or on large TVs. Using the same code base to adapt your application to such a variety of screen sizes and pixel densities is always a challenge. There are no hard and fast rules for designing responsive layouts in the shuttle. In this article, I'll show you some ways to follow when designing such layouts. Before continuing to build a responsive layout in fluent, I want to explain
How Android and iOS handle native layouts with different screen sizes. Well, let's start, but first, let's know
How many mobile application projects do you have in the Git repository?
Android method
In order to handle different screen sizes and pixel densities, the following concepts are used in Android:
1. Constraint layout
One of the revolutionary tools for UI design introduced in the Android world is? ConstraintLayout. It can be used to create flexible and responsive UI designs that adapt to different screen sizes and sizes. Constraintlayout allows you to specify the location and size of each view based on its spatial relationship with other views in the layout.
But this does not solve the problem of large devices. In this case, just stretching or resizing UI components is not the most elegant way to use screen space. This also applies to devices like smart watches, which have small screen space, and resizing components to fit the screen size may lead to strange UI.
2. Alternative layout
To solve the above problems, you can use alternative layouts for devices of different sizes. For example, you can use split views in devices such as tablets to provide a good user experience and use large screen space wisely.! [

In Android, you can define different screen sizes
Separate layout files, the Android framework will automatically handle the switching between these layouts according to the screen size of the device[
? keep abreast of application development news
3. Fragment
With? Fragment, you can extract UI logic into separate components so that when designing a multi pane layout for a large screen size, you do not have to define logic separately. You can reuse the logic you define for each fragment.
4. Vector graphics
In contrast to pixel bitmap creation, vector graphics are images defined as paths and colors in XML files. They can be scaled to any size without scaling artifacts. In Android, you can use? VectorDrawable for any type of illustration, such as icons.
iOS method
The concepts used by iOS to define responsive layout are as follows:
1. Automatic layout
? automatic layout can be used to build an adaptive interface in which you can define rules (called constraints) to manage application content. When some environmental changes (called characteristics) are detected, automatic layout will automatically readjust the layout according to the specified constraints.
2. Size grade
Size classes are features that are automatically assigned to the content area according to the size. iOS dynamically adjusts the layout according to the size category of the content area. On the iPad, size classes are also applicable when your app is running in multi tasking configuration.
3. Some UI elements
There are other UI elements that can be used to build responsive UI on iOS, such as? UIStackView,? UIViewController, and [? UISplitViewController.
How is Flutter different
Even if you are not an Android or iOS developer, you should already know how these platforms handle native responses. In Android, to display multiple UI views on a single screen, you can use Fragments, which are like reusable components that can run within an application's Activity.
You can run multiple fragments in one Activity, but you cannot run multiple activities in a single application at the same time.
In iOS, UISplitViewController manages sub view controllers with a hierarchical interface to control multiple view controllers. Now, let's continue the discussion
Flutter. Flutter introduces[
? the concept of widgets. Basically, they are building blocks that can be connected together to build the entire application.
Remember that in fluent, every screen and even the entire application are widgets!
Widgets are reusable in nature, so you don't need to learn any other concepts when building responsive layouts in fluent.
Responsiveness in fluent
As I said earlier, I'll introduce the important concepts needed to develop responsive layouts, and then you can choose how to implement them in your application.
1. Media query
You can use MediaQuery to retrieve the screen size (width / height) and orientation (vertical / horizontal). An example is as follows:
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { Size screenSize = MediaQuery.of(context).size; Orientation orientation = MediaQuery.of(context).orientation; return Scaffold( body: Container( color: CustomColors.android, child: Center( child: Text( 'View\n\n' + '[MediaQuery width]: ${screenSize.width.toStringAsFixed(2)}\n\n' + '[MediaQuery orientation]: $orientation', style: TextStyle(color: Colors.white, fontSize: 18), ), ), ), ); } }

2. Layout builder
Using the [? LayoutBuilder class, you can obtain the [? BoxConstraints object, which can be used to determine the maxWidth and maxHeight of the widget.
Remember: the main difference between MediaQuery and LayoutBuilder is that MediaQuery uses the full range of the screen, not just the size of your specific icon, while LayoutBuilder can determine the maximum width and height of a specific part.
Examples of this are as follows:
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { Size screenSize = MediaQuery.of(context).size; return Scaffold( body: Row( children: [ Expanded( flex: 2, child: LayoutBuilder( builder: (context, constraints) => Container( color: CustomColors.android, child: Center( child: Text( 'View 1\n\n' + '[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' + '[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}', style: TextStyle(color: Colors.white, fontSize: 18), ), ), ), ), ), Expanded( flex: 3, child: LayoutBuilder( builder: (context, constraints) => Container( color: Colors.white, child: Center( child: Text( 'View 2\n\n' + '[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' + '[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}', style: TextStyle(color: CustomColors.android, fontSize: 18), ), ), ), ), ), ], ), ); } }

3. Current direction
To determine the current orientation of the widget, you can use the [? OrientationBuilder class.
**Remember: * * this is different from the device direction you can use to retrieve MediaQuery.
Examples of this are as follows:
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { Orientation deviceOrientation = MediaQuery.of(context).orientation; return Scaffold( body: Column( children: [ Expanded( flex: 2, child: Container( color: CustomColors.android, child: OrientationBuilder( builder: (context, orientation) => Center( child: Text( 'View 1\n\n' + '[MediaQuery orientation]:\n$deviceOrientation\n\n' + '[OrientationBuilder]:\n$orientation', style: TextStyle(color: Colors.white, fontSize: 18), ), ), ), ), ), Expanded( flex: 3, child: OrientationBuilder( builder: (context, orientation) => Container( color: Colors.white, child: Center( child: Text( 'View 2\n\n' + '[MediaQuery orientation]:\n$deviceOrientation\n\n' + '[OrientationBuilder]:\n$orientation', style: TextStyle(color: CustomColors.android, fontSize: 18), ), ), ), ), ), ], ), ); } }

4. Scalability and flexibility
A particularly useful widget in aColumn or aRow is Expandedand Flexible. The "extension" extends the children of rows, columns, or Flex to fill the available space, while "flexible" does not necessarily fill the entire available space. An example shows various combinations given
Expanded and Flexible are as follows:
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( children: [ Row( children: [ ExpandedWidget(), FlexibleWidget(), ], ), Row( children: [ ExpandedWidget(), ExpandedWidget(), ], ), Row( children: [ FlexibleWidget(), FlexibleWidget(), ], ), Row( children: [ FlexibleWidget(), ExpandedWidget(), ], ), ], ), ), ); } } class ExpandedWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Expanded( child: Container( decoration: BoxDecoration( color: CustomColors.android, border: Border.all(color: Colors.white), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Text( 'Expanded', style: TextStyle(color: Colors.white, fontSize: 24), ), ), ), ); } } class FlexibleWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Flexible( child: Container( decoration: BoxDecoration( color: CustomColors.androidAccent, border: Border.all(color: Colors.white), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Text( 'Flexible', style: TextStyle(color: CustomColors.android, fontSize: 24), ), ), ), ); } }

5. FractionallySizedBox
The FractionallySizedBox widget contributes to a small portion of the total free space of the size and its children. It is particularly useful in internal Expanded or Flexible widgets. An example is as follows:
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ FractionallySizedWidget(widthFactor: 0.4), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ FractionallySizedWidget(widthFactor: 0.6), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ FractionallySizedWidget(widthFactor: 0.8), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ FractionallySizedWidget(widthFactor: 1.0), ], ), ], ), ), ); } } class FractionallySizedWidget extends StatelessWidget { final double widthFactor; FractionallySizedWidget({@required this.widthFactor}); @override Widget build(BuildContext context) { return Expanded( child: FractionallySizedBox( alignment: Alignment.centerLeft, widthFactor: widthFactor, child: Container( decoration: BoxDecoration( color: CustomColors.android, border: Border.all(color: Colors.white), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Text( '${widthFactor * 100}%', style: TextStyle(color: Colors.white, fontSize: 24), ), ), ), ), ); } }

6. Aspect ratio
You can use the? AspectRatio widget to adjust the child to a specific aspect ratio. This widget first tries the maximum width allowed by the layout constraint, and then determines the height by applying the given aspect ratio to the width.
dart class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( children: [ AspectRatioWidget(ratio: '16 / 9'), AspectRatioWidget(ratio: '3 / 2'), ], ), ), ); } } class AspectRatioWidget extends StatelessWidget { final String ratio; AspectRatioWidget({@required this.ratio}); @override Widget build(BuildContext context) { return AspectRatio( aspectRatio: Fraction.fromString(ratio).toDouble(), child: Container( decoration: BoxDecoration( color: CustomColors.android, border: Border.all(color: Colors.white), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Center( child: Text( 'AspectRatio - $ratio', style: TextStyle(color: Colors.white, fontSize: 24), ), ), ), ), ); } }

We've studied most of the important concepts needed to build a responsive layout in fluent, except one. Let's learn the last concept when building a sample responsive application.
Building responsive applications
Now, we will apply some of the concepts I described in the previous section. In addition, you will learn another important concept of building a large screen layout: split view. We will build a
Flow example chat application design.

The application will consist mainly of two main screens:
- Home page (PeopleView, BookmarkView, ContactView)
- Chat page (PeopleView, ChatView)
homepage
After startup, the main screen of the application will be HomePage. It consists of two types of Views:
- HomeViewSmall (including AppBar, Drawer, BottomNavigationBar, and DestinationView)
- HomeViewLarge (DestinationView composed of split view, MenuWidget, and)
dart class _HomePageState extends State { int _currentIndex = 0; @override Widget build(BuildContext context) { return Scaffold( body: LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth < 600) { return HomeViewSmall(); } else { return HomeViewLarge(); } }, ), ); } }
Here, LayoutBuilder is a widget used to determine the switching between maxWidth and HomeViewSmall and HomeViewLarge.
dart class _HomeViewSmallState extends State { int _currentIndex = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // ... ), drawer: Drawer( // ... ), bottomNavigationBar: BottomNavigationBar( // ... ), body: IndexedStack( index: _currentIndex, children: allDestinations.map((Destination destination) { return DestinationView(destination); }).toList(), ), ); } }
IndexedStackwithDestinationView is used to create an index based on the BottomNavigationBar
If you want more information, check out the GitHub repository for this sample application provided at the end of this article.

dart class _HomeViewLargeState extends State { int _index = 0; @override Widget build(BuildContext context) { return Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( flex: 2, child: MenuWidget( selectedIndex: _index, onTapped: (selectedIndex) { setState(() { _index = selectedIndex; }); }, ), ), Expanded( flex: 3, child: IndexedStack( index: _index, children: allDestinations.map((Destination destination) { return DestinationView(destination); }).toList(), ), ), ], ), ); } }
For the large screen, we will display the split view DestinationView containing the MenuWidget and. As you can see, it's really easy to create split views in fluent. You just use a to place them side by side in the Row, and then, to fill the entire space, you just wrap the two views with the Expanded widget. You can also define the flex property Expanded for widgets, which lets you specify how many screens each widget should cover (Flex is set to 1 by default).!

But now, if you move to a specific screen and switch between views, you will lose the context of the page; That is, you will always return to the first page, that is
Chats. To solve this problem, I used multiple callback functions to return the selected page to the HomePage. In fact, you should use state management technology to deal with this situation. Since the sole purpose of this article is to teach you how to build responsive layouts, I won't cover any complexity of state management. modify
HomeViewSmall:
dart class HomeViewSmall extends StatefulWidget { final int currentIndex; /// Callback function final Function(int selectedIndex) onTapped; HomeViewSmall(this.currentIndex, this.onTapped); @override _HomeViewSmallState createState() => _HomeViewSmallState(); } class _HomeViewSmallState extends State { int _currentIndex = 0; @override void initState() { super.initState(); _currentIndex = widget.currentIndex; } @override Widget build(BuildContext context) { return Scaffold( // ... bottomNavigationBar: BottomNavigationBar( // ... currentIndex: _currentIndex, onTap: (int index) { setState(() { _currentIndex = index; // Invoking the callback widget.onTapped(_currentIndex); }); }, items: allDestinations.map((Destination destination) { return BottomNavigationBarItem( icon: Icon(destination.icon), label: destination.title, ); }).toList(), ), ); } }
Modify HomeViewLarge:
dart class HomeViewLarge extends StatefulWidget { final int currentIndex; /// Callback function final Function(int selectedIndex) onTapped; HomeViewLarge(this.currentIndex, this.onTapped); @override _HomeViewLargeState createState() => _HomeViewLargeState(); } class _HomeViewLargeState extends State { int _index = 0; @override void initState() { super.initState(); _index = widget.currentIndex; } @override Widget build(BuildContext context) { return Container( child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( flex: 2, child: MenuWidget( selectedIndex: _index, onTapped: (selectedIndex) { setState(() { _index = selectedIndex; // Invoking the callback widget.onTapped(_index); }); }, ), ), // ... ], ), ); } } ```dart modify`HomePage`:
dart
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold( body: LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth < 600) { return HomeViewSmall(_currentIndex, (index) { setState(() { _currentIndex = index; }); }); } else { return HomeViewLarge(_currentIndex, (index) { setState(() { _currentIndex = index; }); }); } }, ), );
}
}
Now, your response is complete`HomePage`Completed. ### Chat page This will be similar to`HomePage`,However, it will contain the following two views: - **ChatViewSmall**(include`AppBar`,`ChatList`,and`SendWidget`Plug in) - **ChatViewLarge**(include`PeopleView`,`ChatList`,and`SendWidget`Plug in) ```dart dart class ChatPage extends StatelessWidget { final Color profileIconColor; ChatPage(this.profileIconColor); @override Widget build(BuildContext context) { return Scaffold( body: OrientationBuilder( builder: (context, orientation) => LayoutBuilder( builder: (context, constraints) { double breakpointWidth = orientation == Orientation.portrait ? 600 : 800; if (constraints.maxWidth < breakpointWidth) { return ChatViewSmall(profileIconColor); } else { return ChatViewLarge(profileIconColor); } }, ), ), ); } }
Here, I use OrientationBuilder LayoutBuilder to change the breakpointWidth according to the direction, because I don't want PeopleView to be displayed on a small screen phone when it is in landscape mode.
dart class ChatViewSmall extends StatelessWidget { final Color profileIconColor; ChatViewSmall(this.profileIconColor); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( ), body: Container( color: Colors.white, child: Column( children: [ Expanded(child: ChatList(profileIconColor)), SendWidget(), ], ), ), ); } }

dart class ChatViewLarge extends StatelessWidget { final Color profileIconColor; ChatViewLarge(this.profileIconColor); @override Widget build(BuildContext context) { return Container( child: Row( children: [ Expanded( flex: 2, child: SingleChildScrollView( child: PeopleView(), ), ), Expanded( flex: 3, child: Container( color: Colors.white, child: Column( children: [ Expanded(child: ChatList(profileIconColor)), SendWidget(), ], ), ), ), ], ), ); } }

conclusion
We have successfully created a fully responsive application in fluent. You can still make many improvements to this application, one of which may be to define different fontsizes according to different screen sizes. Some of the amazing Flutter plug-ins you can use when using responsiveness are as follows:
- ?device_preview
- ?device_preview
- ?responsive_builde
- ?https://pub.dev/packages/responsive_framework