Responsiveness in Flutter, the Right Way

RotenKiwi
10 min readApr 11, 2023

--

Adding Responsive to Widgets in Flutter

RResponsive UI changes the UI elements of the application according to the size of the different screens, which include mobile phones, tablets, desktop view, Websites, Smart wear such as watches, Television screens, etc. Responsive UI also rearranges the UI according to the orientation of the device and size.
Remember, Responsive and Adaptive are two different virtues of a Flutter application.

Need of Responsive Design

Cost Effective

Maintaining separate applications for your mobile and non-mobile audiences can get expensive. By using responsive design, you can save money by eliminating the cost of paying for a non-mobile application.

Flexibility

When you have an application with responsive design, you can make changes quickly and easily. You do not need to worry about making changes on two apps. This flexibility is a huge advantage when you just want to make a quick design tweak or fix a typo on your app — you only have to do it once.

Improved user experience

User experience is crucial to app owners. You want people to like your app, and you want it to be easy to use to convince them to come back. If someone visits your app on a non-mobile device, and it takes forever to load, or your pictures do not have the proper resolution, it can make your company appear unprofessional.

Ease of management

Rather than having to hire a designer to handle every aspect of your app, responsive design allows you to make the changes yourself, quickly and easily. Additionally, with just one app, other elements of your marketing will be much easier to manage.

Design for every screen size

Using third party Libraries (Packages)

Though using packages or third party libraries may seem the easiest and hassle free solution to make your application responsive, it always comes bearing a cost.
In case of a bug in the package, or if the package is not updated on time for the newer versions of Dart and Flutter, you may have to wait for the fix, or repair them on your own.
Even this comes with loads of work, and if the package has no proper documentation then it becomes even greater headache.

Logical Pixels

Logical Pixels promise you that your widget will have the same physical size on all devices.
This means, if your widget has the size of your thumb on your device, it will have the size of your thumb on all devices.
(Roughly. There are some factors which might make a widget slightly smaller or larger depending on the device).
Logical Pixel can be defined as the number of device pixels for each logical pixel for the screen this view is displayed on. This number(logical pixel) might not be a power of two. Indeed, it might not even be an integer. For example, the Nexus 6 has a device pixel ratio of 3.5.
Logical Pixels are the size measurement that Flutter uses.
Container( height: 40, ) . Here the width: 40 signifies 40 logical pixels and not physical pixels.

Now that we have covered the logical pixels feature, we can move onwards. Regarding Responsive designs in Flutter, the framework already has more than enough widgets and provisions for the same. Let us begin with a few notable ones.

MediaQuery

MediaQuery widget carries information about a piece of media. Media in this case includes the window with its size or orientation. MediaQuery also plays an important role in obtaining or controlling the size of the current window of the device. Either it could be a browser, in case of Flutter web application. Or it could be a size of the mobile device where our Flutter application is running. An important feature of MediaQuery is, it’s always there. We can simply access in the build method by calling MediaQuery.of function.
Even though we see extensive use of MediaQuery class in various Flutter tutorials, there are a few things that we need to understand about the MediaQuery functions,
MediaQuery.of(context).size.width will not give you the exact width in pixels for your physical device measurements but rather in logical pixels. The exact physical device measurements can be acquired in the following manner,
MediaQuery.of(context).size.width * MediaQuery.of(context).devicePixelRatio .
An in-depth guide for the MediaQuery class is given here.

LayoutBuilder

The LayoutBuilder widget in Flutter helps you build a widget tree that can depend on the parent widget’s size (a minimum and maximum width, and a minimum and maximum height).

LayoutBuilder(
builder: (BuildContext context, BoxConstraint constraints) {
return /* your widget tree here */
},
)

Flutter can take the layout builder as a parameter. It has two parameters. Build Context and BoxConstraint. Build Context refers to a widget, while BoxConstraint gives the width to the parent widget which is used to manage the child according to the size of the parent. One important thing to remember is that the Layout Builder's final size will match its child’s size.

The main difference between Media Query and LayoutBuilder is that Media Query uses the full context of the screen instead of the size of your particular widget. While the layout builder can determine the maximum width and height of any widget.

Expanded and Flexible Widgets

Expanded: The Expanded Widget is a single child widget. This means that it can have only one child assigned to it. To make this widget work properly, it must be used inside a row or column. The way Expanded Widget works is that it expands a child of a Row, Column or Flex so that the child fills up the available space. Using an Expanded widget makes a child of a Row, Column, or Flex expand to fill the available space along the main axis (e.g., horizontally for a Row or vertically for a Column). If multiple children are expanded, the available space is divided among them according to the flex factor.

Expanded(
child: Container(
color: Colors.amber,
width: 100,
),
),

Flexible: Flexible widgets are basically similar to extends widgets. But there is a slight difference in properties. It is mainly used to adjust different child widgets’ location while having a relationship with their parent widgets. Flexible widget has a fit property which controls how the child widget fills up the available space. It has two FlexFit values,
1. FlexFit.tight : Sets it to fill the remaining available space.
2. FlexFit.loose : The child can be at most as large as the available space (but is allowed to be smaller).
The Flexible widget also has the Flex property that uses the flex factor to scale its child.

Flexible(
flex: 1, // default value
fit: FlexFit.loose, //default value
child: Container(), // required field
),

Constraints and Aspect Ratio

Aspect Ratio is a widget that attempts to size the child to a specific aspect ratio. The widget first tries the largest width permitted by the layout constraints. The height of the widget is determined by applying the given aspect ratio to the width, expressed as a ratio of width to height.
For example, a 16:9 width:height aspect ratio would have a value of 16.0/9.0. If the maximum width is infinite, the initial width is determined by applying the aspect ratio to the maximum height.

return Container(
color: Colors.blue,
alignment: Alignment.center,
width: 100.0,
height: 100.0,
child: AspectRatio(
aspectRatio: 2:0,
child: Container(
width: 100.0,
height: 50.0,
color: Colors.green,
),
),
);
finite width

Constraint are used to specify the minimum and maximum width and height of your UI elements. This will ensure that your UI elements don’t get too small or too big on different screen sizes.

This results in a great synergy between Constraints and Aspect Ratio as using Constraints allow you to set a minimum and maximum value for your widget and Aspect Ratio can resize them widgets within the constraint range.

The above Mentioned methods are some of the most used methods for generating a Responsive User Interface in Flutter, but this does not mean they are the only ones. There are various other Widgets and packages that can be used for implementing responsiveness into your Flutter Application such as using the Wrap widget, Using ListView and GridView to create scroll-able lists and grids that can adjust to different screen sizes.
You may also use third party libraries and packages such as flutter_screenutil, which makes your UI elements responsive to the screen size, or flutter_spinkit, which provides a collection of animated loading indicators. These plugins can help you to make your application responsive and improve its user experience.

Preferred Way of Sizing Widget

The Preferred way of Sizing your Flutter Widgets is, in order of importance, this :

  1. Do NOT size your Widgets :
    Most widgets dont need an explicit size. They can simply take up the space they need.
    If your widget needs to span a width or height of some other widget or even the screen,
    then you can use a Column or Row with an Expanded or a Flexible. Column and Row are the most basic and commonly used tools to layout your widgets. Try to use them first before looking at other methods.
  2. Logical Pixel Size :
    If your widget explicitly needs a size, then use Logical Pixels. Logical Pixels are the size measurement that flutter uses. Logical Pixels promise you that your widget will have the same physical size on all devices.
    This means, if your widget has the size of your thumb on your device, it will have the size of your thumb on all devices.
    (Roughly. There are some factors which might make a widget slightly smaller or larger depending on the device).
  3. Use LayoutBuilder or MediaQuery
    If you really need to size your widget depending on another widget it is in, or the screen, then use either the Layout Builders, which can be used to read the size of the widget you are in, or the MediaQuery, which can be used to read the size of the App Window (this is NOT the screen size).
    These two tools are useful for showing different layouts of your screens.
    Generally, LayoutBuilder is the more desirable option as your widgets can then be arbitrarily wrapped in other widgets.

On responsive designs Neither MediaQuery nor LayoutBuilder should be used to scale your widgets directly in a multiplicative manner. (For example, never do this: screenSize * 0.5). This will only lead to issues on very large or very small screens. This is also the reason why packages like size_config should be avoided whenever possible.
In the same manner, you should AVOID sizing Fonts based on Screen Sizes. Flutter handles scaling your Fonts appropriately already. Packages like auto_size_text lead to the same problem mentioned above.

Effective ways of deciding what layout to show can be achieved through breakpoints.
In Flutter, breakpoints are used to determine when to change the layout of your application based on the screen size. Breakpoints are predefined screen sizes at which the layout changes to provide the best user experience on different devices.

Different breakpoints for Different screen sizes

Material Design, which is a design system created by Google, has defined breakpoints that can be used in Flutter applications. These breakpoints are commonly used in Flutter because they provide a consistent and reliable way to determine the optimal layout for different screen sizes.

There are packages available on pub.dev, which is the official package repository for Flutter, that provide predefined breakpoints or enable you to use custom breakpoints in a controlled way. Some popular packages that provide predefined breakpoints include responsive_framework, flutter_screenutil, and flutter_responsive_breakpoints. These packages make it easy to implement responsive design in your Flutter application by providing you with tools to determine the optimal layout for different screen sizes.

For example, the responsive_framework package provides predefined breakpoints that correspond to common screen sizes, such as mobile, tablet, and desktop. You can use these breakpoints to adjust your UI based on the current screen size. The package also provides widgets that make it easy to create responsive layouts, such as ResponsiveRow and ResponsiveColumn, which adjust their layout based on the available screen space.

Using breakpoints in your Flutter application can help you to create a responsive design that looks good on all devices. By using packages that provide predefined breakpoints or enabling custom breakpoints, you can ensure that your application provides the best user experience on devices of different sizes.

Wrapping Up

In conclusion, creating a responsive Flutter application is critical to ensure that your users have an optimal experience on all devices. To achieve this, you should consider the screen sizes of various devices and adjust your UI to adapt to them.
Make sure to avoid using MediaQuery and LayoutBuilder for scaling your UI widgets, also any other methods that make use of screenSize or Parent Size.
Additionally, you should test your application on multiple devices to ensure that it looks and functions as intended. By designing your application with different screen sizes in mind and testing it on various devices, you can create a responsive Flutter application that meets the needs of your users and provides them with an excellent user experience.

RotenKiwi

Thanks a Lot for reading and don’t forget to 👏 it helps out a lot.
Share and Comment if you found this blog interesting.
Connect with me on
GitHub , GitLab , LinkedIn , Twitter

--

--

RotenKiwi

A procrastinator writing his thoughts online. 22-year Self-taught Developer.