Build Responsive Layout In Flutter: Part 1

Mohamed Abdo Elnashar
Flutter UAE
Published in
6 min readMar 6, 2023

Flutter is a popular open-source framework used for developing cross-platform mobile applications. It offers a wide range of features and tools that allow developers to create dynamic and responsive layouts for their apps. In this article, we will explore how to build a responsive layout in Flutter.

What is a responsive layout?

A responsive layout is one that adapts to different screen sizes and orientations. With the vast number of devices available in the market, it is crucial to ensure that your app looks good and functions well on all of them. A responsive layout allows your app to adjust its design based on the size and resolution of the device it is running on. This ensures that your app is easy to use and provides a seamless experience to users, regardless of the device they are using.

Building a responsive layout in Flutter

Flutter provides several tools and widgets to help developers create responsive layouts. Let’s take a look at some of the key components that can be used to build a responsive layout in Flutter.

1- MediaQuery

The MediaQuery widget allows you to access the current screen size and other device parameters, such as the orientation of the screen. You can use this information to adjust the size and layout of your widgets based on the device’s screen size.

2- LayoutBuilder Widget

The LayoutBuilder widget provides information about the constraints placed on a widget by its parent. It allows you to access the maximum and minimum width and height that a widget can take. You can use this information to create layouts that adjust to the available space.

First Create widget Called Responsive

to pass three different layouts mobile, tablet, and desktop, and detect which platform you used (by using MediaQuery) and draw it.

how to know the platform by MediaQuery?

  • Mobile is ( MediaQuery.of(context).size.width < 600 ).
  • The tablet is ( MediaQuery.of(context).size.width < 1000 &&
    MediaQuery.of(context).size.width >= 600 ).
  • Desktop is ( MediaQuery.of(context).size.width >= 1000 ).
import 'package:flutter/material.dart';

class Responsive extends StatelessWidget {
final Widget mobile;
final Widget tablet;
final Widget desktop;
const Responsive({
Key? key,
required this.mobile,
required this.tablet,
required this.desktop,
}) : super(key: key);

static bool isMobile(BuildContext context) =>
MediaQuery.of(context).size.width < 600;

static bool isTablet(BuildContext context) =>
MediaQuery.of(context).size.width < 1000 &&
MediaQuery.of(context).size.width >= 600;

static bool isDesktop(BuildContext context) =>
MediaQuery.of(context).size.width >= 1000;

@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 1000) {
return desktop;
} else if (constraints.maxWidth >= 600) {
return tablet;
} else {
return mobile;
}
},
);
}
}

Create UI class

To init custom size of properties such as width, height, horizontal, vertical, padding, and diagonal.

import 'dart:math';
import 'package:flutter/widgets.dart';

class UI {
static MediaQueryData? _mediaQueryData;
static double? width;
static double? height;
static double? horizontal;
static double? vertical;
static EdgeInsets? padding;
static EdgeInsets? vi;

static double? _safeAreaHorizontal;
static double? _safeAreaVertical;
static double? safeWidth;
static double? safeHeight;

static double? diagonal;

static bool? xxs;
static bool? xs;
static bool? sm;
static bool? md;
static bool? xmd;
static bool? lg;
static bool? xl;
static bool? xlg;
static bool? xxlg;

static void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
initChecks(_mediaQueryData!);

padding = _mediaQueryData!.padding;
vi = _mediaQueryData!.viewInsets;
width = _mediaQueryData!.size.width;
height = _mediaQueryData!.size.height;
horizontal = width! / 100;
vertical = height! / 100;

_safeAreaHorizontal =
_mediaQueryData!.padding.left + _mediaQueryData!.padding.right;
_safeAreaVertical =
_mediaQueryData!.padding.top + _mediaQueryData!.padding.bottom;
safeWidth = (width! - _safeAreaHorizontal!);
safeHeight = (height! - _safeAreaVertical!);
}

static initChecks(MediaQueryData query) {
var size = query.size;
diagonal = sqrt((size.width * size.width) + (size.height * size.height));
xxs = size.width > 300;
xs = size.width > 360;
sm = size.width > 480;
md = size.width > 600;
xmd = size.width > 720;
lg = size.width > 980;
xl = size.width > 1160;
xlg = size.width > 1400;
xxlg = size.width > 1700;
}

static MediaQueryData mediaQuery() => _mediaQueryData!;

static Size getSize() => _mediaQueryData!.size;
}

Create AppDimensions based on UI class

Define custom methods such as space, normalize, and font, to return new values depending on the platform.

import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'ui.dart';

class AppDimensions {
static double? maxContainerWidth;
static double? miniContainerWidth;

static bool? isLandscape;
static double? padding;
static double ratio = 0;

static Size? size;

static init() {
ratio = UI.width! / UI.height!;
double pixelDensity = UI.mediaQuery().devicePixelRatio;
ratio = (ratio) + ((pixelDensity + ratio) / 2);

if (UI.width! <= 380 && pixelDensity >= 3) {
ratio *= 0.85;
}

_initLargeScreens();
_initSmallScreensHighDensity();

padding = ratio * 3;
}

static _initLargeScreens() {
const safe = 2.4;

ratio *= 1.5;

if (ratio > safe) {
ratio = safe;
}
}

static _initSmallScreensHighDensity() {
if (!UI.sm! && ratio > 2.0) {
ratio = 2.0;
}
if (!UI.xs! && ratio > 1.6) {
ratio = 1.6;
}
if (!UI.xxs! && ratio > 1.4) {
ratio = 1.4;
}
}

static String inString() {
final x = UI.width! / UI.height!;
final ps = ui.window.physicalSize;
return """
Width: ${UI.width} | ${ps.width}
Height: ${UI.height} | ${ps.height}
app_ratio: $ratio
ratio: $x
pixels: ${UI.mediaQuery().devicePixelRatio}
""";
}

static double space([double multiplier = 1.0]) {
return AppDimensions.padding! * 3 * multiplier;
}

static double normalize(double unit) {
return (AppDimensions.ratio * unit * 0.77) + unit;
}

static double font(double unit) {
return (AppDimensions.ratio * unit * 0.125) + unit * 1.90;
}
}

Create AppSetting based on UI and AppDimensions class

the job of this class only init all variables of both class UI and AppDimensions

import 'package:flutter/material.dart';
import 'app_dimensions.dart';
import 'ui.dart';

class AppSetting {
static init(BuildContext context) {
UI.init(context);
AppDimensions.init();
}
}

Finally, we finished the definition of base Class

let’s go to used this class in our app

Create a HomeScreen page it will be called the Responsive widget and pass three different layouts and get init from AppSetting class

import 'package:flutter/material.dart';
import '../responsive/responsive.dart';
import '../configs/app.dart';
import 'items/desktop.dart';
import 'items/mobile.dart';
import 'items/tablet.dart';

class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
AppSetting.init(context);

return const Responsive(
mobile: MyHomeMobile(),
tablet: MyHomeTablet(),
desktop: MyHomeDesktop(),
);
}
}

And implementation of three layouts (mobile, tablet, and desktop) widgets

import 'package:flutter/material.dart';
import '../../configs/app_dimensions.dart';

class MyHomeDesktop extends StatelessWidget {
const MyHomeDesktop({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Text(
"Desktop",
style: TextStyle(fontSize: AppDimensions.font(20)),
),
);
}
}
import 'package:flutter/material.dart';
import '../../configs/app_dimensions.dart';

class MyHomeTablet extends StatelessWidget {
const MyHomeTablet({super.key});

@override
Widget build(BuildContext context) {
return Center(
child: Text(
"Tablet",
style: TextStyle(fontSize: AppDimensions.font(20)),
),
);
}
}
import 'package:flutter/material.dart';
import '../../configs/app_dimensions.dart';

class MyHomeMobile extends StatelessWidget {
const MyHomeMobile({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Center(
child: Text(
"Mobile",
style: TextStyle(fontSize: AppDimensions.font(20)),
),
);
}
}

using AppDimensions.font(20) to set the font size to this text.

Thanks to Muhammad Hamza his github help me.

I hope you all liked this blog and it helped you get started with Flutter! Don’t forget to smash that clap button and leave a comment down below.

Meet you at the next one.

--

--

Mohamed Abdo Elnashar
Flutter UAE

Senior Flutter Developer, and I study a master of computer science in the faculty of computer & information sciences at Mansoura university