Responsive design is easy with Flutter

The Age of Connectivity and the popularity of mobile devices have made responsive UI a standard that website and app users expect out of sheer convenience. While successful responsive design can be achieved by many frameworks out there, it’s worth paying special attention to the one that offers cross-platform support even for your toaster: Flutter. What are its benefits and functionalities that can work to your advantage when designing responsive apps and websites? Explore with us the possibilities which Flutter offers for successful responsive design and develop your skills.

The importance and current state of Responsive Design

Flutter keeps expanding its cross-platform support by including Web, Linux, Windows, and recently MacOS. Even though the support for certain platforms is still at the very beginning of their journey, it surely is changing software development traditions.

Just as the sheer number of devices increases, the same applies to the variety of screen sizes available, highlighting the importance of a neat design. As the appearance of websites and applications changes with different screen sizes of the devices used, it becomes crucial to maintain a neat design. And by neat, we mean responsive. Before we discuss the functionalities of the specific widgets that facilitate effective designing of responsive websites, let us first explore the current trends in screen sizes and device types.

Deciding on the screen type

As screen orientation changes significantly the way a website or application looks, we cannot talk about quality user experience without responsive design, which takes this aspect into account. What if the orientation of the screen is “landscape” instead of “portrait”? This is for sure a case for mobile device and tablet users. To provide the best user experience in responsive design, the app or website should have our input about the screen size, i.e., its width and orientation. 

In this context, it is crucial to be aware of the trends concerning screen sizes and device types.

For example, take a look at the 2019-2020 trends in user screen sizes:

  • Desktop Screen Resolution Stats Worldwide May 2019 – May 2020

1366×768 – 23.49%
1920×1080 – 19.91%
1536×864 – 8.65%
1440×900 – 7.38%
1280×720 – 4.89%
1600×900 – 4.01%
1280×800 – 3.33%

  • Mobile Screen Resolution Stats Worldwide May 2019 – May 2020

360×640 – 17.91%
375×667 – 7.61%
414×896 – 6.52%
360×780 – 5.56%
360×760 – 5.06%
414×736 – 3.74%

  • Tablet Screen Resolution Stats Worldwide May 2019 – May 2020

768×1024 – 51.98%
1280×800 – 7.11%
800×1280 – 5.34%
601×962 – 4.47%
600×1024 – 2.85%
1024×1366 – 1.96%

You can read further about the Best Screen Sizes For Responsive Web Design here.

Based on these stats, let’s generalise that: 

screenWidth > 1366px is best for a Desktop
screenWidth <= 1366px and screenWidth > 768px is best for a Tablet
screenWidth <= 768px is best for Mobile devices   

//Assuming that "deviceType" is accepting some sort of enum
if (screenWidth <= 768) {
deviceType = mobile;
} else if (screenWidth <= 1366) {
deviceType = tablet;
} else {
deviceType = desktop;
}

Hungry for more knowledge? Read about the same trends and frameworks in the context of cross-platform mobile app development.

MediaQuery vs. LayoutBuilder

Based on the Flutter docs, there are two options to make your design responsive in Flutter.

  1. MediaQuery
  2. LayoutBuilder

What exactly are their functional advantages and when, if at all, should we use one over the other? Read on to find out.

Good Old MediaQuery

MediaQuery object is a repository of information about the screen in Flutter. The MediaQuery object itself doesn’t include much, except the MediaQueryData property. Truth is, we would use the MediaQuery object to get the MediaQueryData object, most of the time.

The MediaQueryData object returns information about the app's window. In a mobile app, this would correspond to your device's screen. The screen size and orientation can be obtained by accessing its properties.

double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
Orientation orientation = MediaQuery.of(context).orientation;

print(screenWidth.toString());
print(screenHeight.toString());
print(orientation.toString());

Did you realize that the numbers printed on the screen change as soon as the window size changes? This means that the widget gets rebuilt each time the corresponding MediaQueryData object changes, which increases its usefulness in designing responsive UI.

LayoutBuilders

LayoutBuilder is a Flutter widget that allows developers to build their widgets inside a constrained environment. In other words, it allows you to prepare a widget with an assumption of the available size other than the device’s screen size.

Similar to the MediaQueryData object, here we get a BoxConstraints object. This object includes the maximum and minimum dimensions that our widget can possibly have. 

It’s quite handy when the size of your child widget relies heavily on the parent widget dimensions.

LayoutBuilder(
builder: (context, constraints) {
double widgetWidth = constraints.maxWidth;
double widgetHeight = constraints.maxHeight;

if (widgetWidth <= 600) {
screenType = 'small';
} else if (widgetWidth <= 1200) {
screenType = 'large';
}

//...returns a widget
},
)

When to choose the MediaQuery over LayoutBuilder?

The Flutter documentation doesn’t in detail specify the advantages or disadvantages of LayoutBuilder and MediaQuery. You can use LayoutBuilder instead of MediaQuery; however, these two classes are made for different purposes. 

  • MediaQuery is useful if your widget is interested in the entire screen. Since this is treated as “Media”, in an application it will provide you with crucial information about the screen’s orientation and resolution.
  • LayoutBuilder is useful when your widget is interested in the available space indicated by the parent widget. It won’t, however, give you any additional information about the application’s window. 

All in all, we cannot choose one class over the other, as both MediaQuery and LayoutBuilder cooperate with one another by effectively facilitating the completion of their intended purposes.

What else is there to make an app responsive? 

Is that all which Flutter offers to build an app that looks professional? While we won’t be discussing every single widget in this very article, there are a few of them in Flutter that especially come in handy for responsive design.

  1. OrientationBuilder
  2. SafeArea
  3. AspectRatio
  4. Flexible
  5. Expanded
  6. FractionallySizedBox

OrientationBuilder

This widget is useful, if we change the UI based on the orientation of the parent widget. It obtains the orientation data by comparing the width and the height of the parent widget.

Example: 
You have a grid with the dynamic number of columns. You could use the orientation property of the MediaQuery which will give you the device orientation. But it’s not quite the solution here. Because you may end up having your widget down below the widget tree and the orientation may not be the same as the device orientation. In this case, this builder widget is the solution.

Also, if you develop a reusable Flutter package, it should be compatible with as many cases as possible. This means that the OrientationBuilder is the way to go.

OrientationBuilder(
builder: (context, orientation) {
return GridView.count(
// Create a grid with 2 columns in portrait mode,
// or 3 columns in landscape mode.
crossAxisCount: orientation == Orientation.portrait ? 2 : 3,
);
},
);

SafeArea

We are not always building a fullscreen app. And since the operating system will also have to draw elements such as the status bar, notch, or the buttons at the bottom on the screen, there will be conflicts. Your app’s widgets will be overdrawn with these OS elements, unless the SafeArea is used.

The SafeArea widget lets you avoid this scenario. It adds a sufficient amount of padding to ensure that your widgets are visible at all times. Funny as it is, the amount of padding that SafeArea needs is provided by the MediaQuery object.

AspectRatio

The aspect ratio can be crucial for specific designs. If the screen sizes vary from slim to very wide, then the aspect ratio of a widget should be also kept the same. 

Flutter provides this particular widget when a parent widget has a defined size and the child widget must be modified for a given aspect ratio.

Flexible

Flexible widget is useful for controlling how children of Row, Column, and Flex behave, while the parent changes dimensions. Another cool aspect to it is that an array of Flexible widgets can be also mixed with static widgets.

Expanded

Expanded is a widget that fills all available space inside a Row, Column, or Flex widget. Such a widget is very useful when your widget dimensions are not static. If there are multiple children that share the same space, then they share it based on their “flex factor”.

Expanded vs. Flexible

You may have realized that Flexible and Expanded widgets sound similar. Similar in a way that both widgets are helping us inside the Row, Column, and Flex widgets. What is the difference between them then? Actually, Expanded is a short command for a Flexible widget which has a “fit” attribute set for “tight”:

Flexible (fit: FlexFit.tight) = Expanded()

So, Flexible lets the child have the same or smaller size than the Flexible itself, while Expanded forces its child to have the exact same size itself. Both the Expanded and the Flexible ignore their children’s width when sizing themselves.

FractionallySizedBox

Not everything in Flutter is about pixels and precision. You can also draw a widget by specifying nothing more but percentages. This is great if you need to support different screens or parent widgets. 

Here is an example of a button with 70% of the parent container’s size:

return Container(
color: Colors.white,
child: FractionallySizedBox(
widthFactor: 0.7,
child: FlatButton(
onPressed: () {
print('hi');
},
color: Colors.blue,
child: Text('Say hi'),
),
),
);

It is only a handful of lines which don’t require passing any “width” or constraint. As a result, the amount of code you produce in order to get the same result is drastically reduced.

Flutter knows how to be responsive

By and large, Flutter lives up to the expectations coming along with its support for different platforms (Android, IOS, MacOS, Windows, and Linux), providing easy ways to effectively design responsive websites and apps. Not only does it prove useful in adjusting your design to different devices’ screen sizes and orientations but also - among a crazy number of different widgets - it furnishes us with the ones for specific needs. That being said, while mainly using LayoutBuilder or MediaQuery, we must also orchestrate these tiny but powerful widgets to achieve the perfect UI.

We see that while there are remnants of general responsive design practices such as “flex” or “MediaQuery”, the properties and usage of these objects are slightly different. Nonetheless, we shouldn’t assume that all the needs of responsive designing in Flutter are covered. But it is getting there and it is definitely worth trying out for these purposes.

In this article, we covered only a portion of the Flutter-available widgets related to responsive design. Follow our next reading to learn more!

Interested in expanding your skillset in modern mobile frameworks? Be sure to check out our job offers!

 

Navigate the changing IT landscape

Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .