Widgets sizes relative to screen size in Flutter using MediaQuery

Tagmalogic
tagmalogic
Published in
5 min readJan 4, 2020
Dynamic widget size in Flutter — MediaQuery

OK, have you ever felt like banging your head into a wall when you had your mobile app almost ready and gave a final check on how it looks on different devices with different screen sizes? Well, I felt like that recently :)

Luckily there is a relatively quick fix for this problem in Flutter. We can retrieve the screen size (width or height) and calculate for each widget what ratio shall have relative to the device size. Obviously, this will result in different values for different devices with different screen sizes. And that’s the whole point. The beauty of it is that we just need to retrieve the screen size and then decide what ratio of that size we what for each of our widgets to use, the rest is done automatically for us.

A bit of logic for safety reasons … before coding

We will be using MediaQuery.of(context).size to retrieve the device screen size. Before jumping to some simple code examples we need to understand what the size means in this context. It is not the actual physical resolution in pixels but rather it expresses logical pixels. But that’s exactly what we need. MediaQuery uses a devicePixelRatio property. Basically, if you want to tell the exact physical pixel value of your screen width you will need to do something like this: MediaQuery.of(context).size.width * MediaQuery.of(context).devicePixelRatio . In reality we don’t need to do such calculations in most of the cases as the size properties of Flutter widgets use the logical pixels.

Now, all you need to know really is that you can retrieve the width of the screen with MediaQuery.of(context).size.width and the height of the screen with MediaQuery.of(context).size.height. If you want to get a Size object with both dimensions you can get with with just MediaQuery.of(context).size.

Very important is to use import ‘package:flutter/material.dart’; to be able to use MediaQuery, too.

Retrieving the meaningful height can be tricky

To avoid another head bang onto the wall there is a bit of a trick for the height value that we need to know. The height includes the AppBar and status bar heights, too. Should you look to deduct those from the total height you can retrieve their values. The constant kToolbarHeight has the height value of the AppBar (if you are using the default AppBar height) and with MediaQuery.of(context).padding.top you can retrieve the height of the status bar. Then the actual meaningful screen height will be: MediaQuery.of(context).size.height — MediaQuery.of(context).padding.top — kToolbarHeight . Furthermore, if you use a BottomNavigation bar, the default height is stored in kBottomNavigationBarHeight constant. Naturally, in that case, the screen height will be: MediaQuery.of(context).size.height — MediaQuery.of(context).padding.top — kToolbarHeight — kBottomNavigationBarHeight . Really, all depends on your use case.

Let’s see some code now…

Go ahead and create a new Flutter project. Create a new file called sizes_helpers.dart in the lib folder of the project, besides the main.dart file. Add the following code in your new file:

import 'package:flutter/material.dart';

Size displaySize(BuildContext context) {
debugPrint('Size = ' + MediaQuery.of(context).size.toString());
return MediaQuery.of(context).size;
}

double displayHeight(BuildContext context) {
debugPrint('Height = ' + displaySize(context).height.toString());
return displaySize(context).height;
}

double displayWidth(BuildContext context) {
debugPrint('Width = ' + displaySize(context).width.toString());
return displaySize(context).width;
}

I’ve added a number of debugPrint statements so you can check your logs during execution to see what are the actual values for size, width and height. Keep in mind that those are logical pixels not physical ones.

Add the following code in the main.dart file:

import 'package:flutter/material.dart';
import 'package:sizes/sizes_helpers.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sizes... sizes',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Sizes... sizes'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
color: Colors.red,
width: displayWidth(context) * 0.25,
child: Text(
'Box width 25% of screen width and text size 3% of screen width',
textAlign: TextAlign.center,
style: TextStyle(fontSize: displayWidth(context) * 0.03),
),
),
Container(
color: Colors.green,
width: displayWidth(context) * 0.5,
child: Text(
'Box width 50% of screen width and text size 6% of screen width',
textAlign: TextAlign.center,
style: TextStyle(fontSize: displayWidth(context) * 0.06),
),
),
Container(
color: Colors.blue,
width: displayWidth(context),
child: Text(
'Box width equal to screen width and text size 10% of screen width',
textAlign: TextAlign.center,
style: TextStyle(fontSize: displayWidth(context) * 0.1),
),
),
],
),
),
);
}
}

Although the code is simple and easy to understand please note:

  • we imported the newly created file: import ‘package:sizes/sizes_helpers.dart’;
  • we’ve set the width of the Container widgets as a fraction of the total screen width, i.e. width: displayWidth(context) * 0.25
  • we set the size of the Text widget in the TextStyle widget once again as a fraction of the total screen width, i.e. style: TextStyle(fontSize: displayWidth(context) * 0.03)

Now, go ahead and run your application and you should see something like this…

Now let’s see an example on how to calculate the height of the screen deducting the status bar height and the AppBar height.

Replace the code in main.dart file with the following code:

import 'package:flutter/material.dart';
import 'package:sizes/sizes_helpers.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sizes... sizes',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Sizes... sizes'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
color: Colors.red,
width: displayWidth(context) * 0.5,
height: displayHeight(context) -
MediaQuery.of(context).padding.top -
kToolbarHeight,

child: Text(
'Box width 50% of screen width and text size 6% of screen width and full screen height minus status bar height and AppBar height',
textAlign: TextAlign.center,
style: TextStyle(fontSize: displayWidth(context) * 0.06),
),
),
],
),
),
);
}
}

Before running the code note how we calculate the height property for the Container widget: height: displayHeight(context) -
MediaQuery.of(context).padding.top -
kToolbarHeight
.

Go ahead now and execute your code and you should see something like below:

I hope you enjoyed the reading and that it was useful for you.

Do not hesitate to leave comments bellow on what you liked, you did not like so much, what you want to see more or just … clap and share if you found this article useful.

--

--

Tagmalogic
tagmalogic

Where journey meets the destination — magic tech!