How to create landscape layouts in Flutter

An overwhelming majority of Flutter code tutorials show phone screens in portrait mode. But what about tablets and landscape mode? Android comes with a system to specify layouts per orientation – can you do this with Flutter?

When I created my first Flutter app Crosswords to learn French, I locked it to portrait mode. This was fine for v1.0, but for v1.1, I wanted to add tablet support. This meant allowing landscape mode. To my surprise, it took only about 30 minutes. You read that right, 30 minutes! As I had already put each UI section into its own widget, it was easy to recombine them based on orientation. And retrieving orientation turned out to be easily done, once I knew where to look ( MediaQuery and MediaQueryData).

Portrait, phone
Portrait, phone
Landscape, 10" tablet
Landscape, 10″ tablet

Note: I chose to maximise crossword size, so I decided not to show the custom keyboard view across the full width of the screen, but, technically, I could have done it just as easily.

For this code tutorial, I will use a simplified version of my app UI. We will create the portrait layout, then the landscape layout.

Setting up the app

To follow the code tutorial, create a new app as follows.

If you’re unsure how to set up a Flutter app, check out Getting started with Flutter official tutorial.

Firstly, we create a Material app in main.dart, which will launch the HomePage widget.

 

Secondly, we create home_page.dart. This will eventually display 3 views: crossword, clues, and keyboard. But for now, it just displays a message.

 

Set up the views for portrait mode

Each logical view of the screen, ie crossword, clues, and keyboard, is set up in its own Widget. For simplicity, they are all stateless.

Firstly, we create crossword_view.dart. In this simplified version, it is a grid with 8 rows and 8 columns, with  cells showing as a black or white square.

 

Secondly, we create clues_view.dart. This contains 2 lists of different length, side by side, with equal width. Above each list, there is a non scrollable label that says either ‘Across’ or ‘Down’. It fits the available width and height.

 

Thirdly, we create keyboard_view.dart. This contains 3 rows of fixed and equal height. It fills the available width.

 

Finally, we combine the views together, for portrait mode. Crossword view has a defined height because shrinkWrap is set to true; keyboard view has a fixed height; clues view fits the rest of the height. Let’s amend home_page.dart.

 

For a reminder on how to use Row and Column, check out Flutter UI code tutorial: mastering Row and Column.

Adapt layout to landscape mode

In Flutter, all UI code is done in Dart, in the build method. So we amend the _buildBody() method in home_page.dart to check the device orientation.

 

Now, we can combine the views together for landscape mode.

 

BUT… it isn’t quite finished yet! The GridView used in crossword view is scrollable, and therefore fills in the available space. The property shrinkWrap forces it to constraint to its content the dimension  in the direction of its scrollable axis. Put simply, if it is scrollable vertically (the default), it will set its height to fit the content, which works great in portrait mode. But in landscape mode, the dimension we need to constraint is the width; if we don’t, the Row widget will throw an error. So we need to check for the orientation in crossword_view.dart.

 

Voila

Portrait
Portrait
Landscape
Landscape

 

 

 

 

 

 

 

What next?

This tutorial shows how to detect the orientation. Flutter Rocks has an excellent tutorial showing how to bring screen size qualifiers to Flutter, in  Implementing adaptive master-detail layouts in Flutter.

 

Author: Natalie Masse Hooper

Mobile app developer with 14 years experience. Started with the Android SDK in 2010 and switched to Flutter in 2017. Past apps range from start ups to large tech (Google) and non tech (British Airways) companies, in various sectors (transport, commercial operations, e-commerce).

Leave a Reply

Your email address will not be published.