{"id":6243,"date":"2022-11-21T14:34:46","date_gmt":"2022-11-21T13:34:46","guid":{"rendered":"https:\/\/kabisa.nl\/?p=6243"},"modified":"2023-10-24T12:27:07","modified_gmt":"2023-10-24T10:27:07","slug":"responsive-design-in-flutter-the-easy-way","status":"publish","type":"post","link":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/","title":{"rendered":"Responsive design in Flutter, the easy way"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"6243\" class=\"elementor elementor-6243\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-d00a3c4 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"d00a3c4\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;jet_parallax_layout_list&quot;:[]}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4fb1817\" data-id=\"4fb1817\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b8d08b4 elementor-widget elementor-widget-text-editor\" data-id=\"b8d08b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and we don\u2019t need to use any third-party package for it! With the release of Flutter 3 we are finally able to extend our ThemeData in an easy way, and it is going to help us to implement responsive designs in our apps!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f9861a elementor-widget elementor-widget-text-editor\" data-id=\"2f9861a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>With a background in web development I am used to creating apps with a responsive design. Responsive design basically means that your application adjusts to various screen sizes. With the switch to Flutter, it became almost immediately clear that it isn\u2019t as straightforward to have global theming adjusted to the screen resolution. There are plenty of packages on\u00a0<a href=\"https:\/\/pub.dev\/\">pub.dev<\/a>\u00a0that try to help you with this but I prefer to have control over behavior myself. Especially when you work on projects where design systems are a thing.<\/p><p>With the addition of the\u00a0<a href=\"https:\/\/api.flutter.dev\/flutter\/material\/ThemeExtension-class.html\">ThemeExtension<\/a>\u00a0class in Flutter 3 I suddenly felt that possibilities started to open. This class allows you to define custom additions to a ThemeData object, awesome \ud83d\udd25!<\/p><h2 id=\"creating-the-theme-extensions\">Creating the theme extensions<\/h2><p>To demonstrate this, I will create two theme extensions. One for custom text styles and another for spacing values that I will use to apply margin and\/or padding in my application. I\u2019ve kept it really simple in this example but there are no limitations in the implementation! Let\u2019s create them first and I will explain it afterwards.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b8d037c elementor-widget elementor-widget-code-highlight\" data-id=\"b8d037c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>@immutable\nclass AppTextStyles extends ThemeExtension<AppTextStyles> {\n  const AppTextStyles({\n    required this.headline1,\n    required this.bodyText1,\n  });\n\n  final TextStyle headline1;\n  final TextStyle bodyText1;\n\n  static const small = AppTextStyles(\n    headline1: TextStyle(fontSize: 24.0),\n    bodyText1: TextStyle(fontSize: 16.0),\n  );\n\n  static const medium = AppTextStyles(\n    headline1: TextStyle(fontSize: 32.0),\n    bodyText1: TextStyle(fontSize: 18.0),\n  );\n\n  static const large = AppTextStyles(\n    headline1: TextStyle(fontSize: 36.0),\n    bodyText1: TextStyle(fontSize: 20.0),\n  );\n\n  @override\n  ThemeExtension<AppTextStyles> copyWith({\n    TextStyle? headline1,\n    TextStyle? bodyText1,\n  }) {\n    return AppTextStyles(\n      headline1: headline1 ?? this.headline1,\n      bodyText1: bodyText1 ?? this.bodyText1,\n    );\n  }\n\n  @override\n  ThemeExtension<AppTextStyles> lerp(\n    ThemeExtension<AppTextStyles>? other,\n    double t,\n  ) {\n    if (other is! AppTextStyles) {\n      return this;\n    }\n    return AppTextStyles(\n      headline1: TextStyle.lerp(headline1, other.headline1, t)!,\n      bodyText1: TextStyle.lerp(bodyText1, other.bodyText1, t)!,\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1317747 elementor-widget elementor-widget-code-highlight\" data-id=\"1317747\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>@immutable\nclass AppSpacings extends ThemeExtension<AppSpacings> {\n  const AppSpacings({\n    required this.s,\n    required this.m,\n    required this.l,\n  });\n\n  final double s;\n  final double m;\n  final double l;\n\n  static const small = AppSpacings(s: 4.0, m: 12.0, l: 20.0);\n  static const medium = AppSpacings(s: 12.0, m: 20.0, l: 28.0);\n  static const large = AppSpacings(s: 20.0, m: 28.0, l: 36.0);\n\n  @override\n  ThemeExtension<AppSpacings> copyWith({\n    double? s,\n    double? m,\n    double? l,\n  }) {\n    return AppSpacings(\n      s: s ?? this.s,\n      m: m ?? this.m,\n      l: l ?? this.l,\n    );\n  }\n\n  @override\n  ThemeExtension<AppSpacings> lerp(\n    ThemeExtension<AppSpacings>? other,\n    double t,\n  ) {\n    if (other is! AppSpacings) {\n      return this;\n    }\n    return AppSpacings(\n      s: lerpDouble(s, other.s, t)!,\n      m: lerpDouble(m, other.m, t)!,\n      l: lerpDouble(l, other.l, t)!,\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9355b19 elementor-widget elementor-widget-text-editor\" data-id=\"9355b19\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ok, that is a big chunk of boilerplate-y code \ud83d\ude05. Lets analyze what I did:<\/p><ul><li>For both extensions I\u2019ve defined three different varieties of the theme.\u00a0<code>small<\/code>,\u00a0<code>medium<\/code>\u00a0and\u00a0<code>large<\/code>, which represent the breakpoints that I will add later in the app itself.<\/li><li>The\u00a0<a href=\"https:\/\/api.flutter.dev\/flutter\/material\/ThemeExtension\/copyWith.html\"><code>copyWith<\/code><\/a>\u00a0method which can be used to create a copy of the extension with the given fields replaced by the non-null parameter values.<\/li><li>The\u00a0<a href=\"https:\/\/api.flutter.dev\/flutter\/material\/ThemeExtension\/lerp.html\"><code>lerp<\/code><\/a>\u00a0method which will ensure smooth transitions of properties when switching themes.<\/li><\/ul><p><strong>Combining extensions<\/strong><\/p><p>To make it easier to create and include other theme extensions in the future, I am going to create a root theme extension that will combine all theme extensions that I create.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e5efcda elementor-widget elementor-widget-code-highlight\" data-id=\"e5efcda\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>class AppThemes extends ThemeExtension<AppThemes> {\n  const AppThemes({\n    required this.appSpacings,\n    required this.appTextStyles,\n  });\n\n  final AppSpacings appSpacings;\n  final AppTextStyles appTextStyles;\n\n  static const AppThemes small = AppThemes(\n    appSpacings: AppSpacings.small,\n    appTextStyles: AppTextStyles.small,\n  );\n\n  static const AppThemes medium = AppThemes(\n    appSpacings: AppSpacings.medium,\n    appTextStyles: AppTextStyles.medium,\n  );\n\n  static const AppThemes large = AppThemes(\n    appSpacings: AppSpacings.large,\n    appTextStyles: AppTextStyles.large,\n  );\n\n  @override\n  ThemeExtension<AppThemes> copyWith({\n    AppTextStyles? appTextStyles,\n    AppSpacings? appSpacings,\n  }) {\n    return AppThemes(\n      appTextStyles: appTextStyles ?? this.appTextStyles,\n      appSpacings: appSpacings ?? this.appSpacings,\n    );\n  }\n\n  @override\n  ThemeExtension<AppThemes> lerp(\n    ThemeExtension<AppThemes>? other,\n    double t,\n  ) {\n    if (other is! AppThemes) {\n      return this;\n    }\n    return AppThemes(\n      appSpacings: other.appSpacings,\n      appTextStyles: other.appTextStyles,\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-50acb05 elementor-widget elementor-widget-text-editor\" data-id=\"50acb05\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 id=\"extending-the-themedata-object\">Extending the ThemeData object<\/h2><p>Now that I\u2019ve defined the theme extensions that I want to use in my app I can make them available in my theme data. I\u2019ve created a class that will hold all my global theme data information. Let\u2019s take a look at the implementation step by step \ud83e\uddd0.<\/p><ul><li>A different\u00a0<code>ThemeData<\/code>\u00a0object is created for the different screen resolutions that I differentiate:\u00a0<code>small<\/code>,\u00a0<code>medium<\/code>, and\u00a0<code>large<\/code>. The root theme extension is referenced, and will include the other extensions.<\/li><li><code>_baseTheme<\/code>\u00a0is the basis for all global theme data information.<\/li><li><code>AppThemes<\/code>\u00a0is added to the\u00a0<code>extensions<\/code>\u00a0argument. This way I can access the (nested) extension information throughout my entire application like\u00a0<code>Theme.of(context).extension&lt;AppThemes&gt;()<\/code>.*<\/li><\/ul><p><em>*You could argue that there is no need for a theme extension for the text styles since that is added to the global text theme, but if you ever find yourself adding custom text styles that are not part of\u00a0<code>TextTheme<\/code>\u00a0(e.g. text style for a link), it is super easy to access that via the theme extension.<\/em><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42b130d elementor-widget elementor-widget-code-highlight\" data-id=\"42b130d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>class ResponsiveTheme {\n  const ResponsiveTheme._();\n\n  static final small = _baseTheme(AppThemes.small);\n  static final medium = _baseTheme(AppThemes.medium);\n  static final large = _baseTheme(AppThemes.large);\n\n  static ThemeData _baseTheme(AppThemes appThemes) {\n    final textStyles = appThemes.appTextStyles;\n    final spacings = appThemes.appSpacings;\n\n    return ThemeData(\n      extensions: [appThemes],\n      textTheme: TextTheme(\n        headline1: textStyles.headline1,\n        bodyText1: textStyles.bodyText1,\n      ),\n      appBarTheme: AppBarTheme(\n        titleTextStyle: textStyles.headline1,\n      ),\n      elevatedButtonTheme: ElevatedButtonThemeData(\n        style: ButtonStyle(\n          padding: MaterialStateProperty.all(EdgeInsets.all(spacings.m)),\n        ),\n      ),\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dd75aef elementor-widget elementor-widget-text-editor\" data-id=\"dd75aef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Next, I\u2019ll use the\u00a0<code>LayoutBuilder<\/code>\u00a0widget to apply the correct theme based on a certain breakpoint. In the\u00a0<code>ResponsiveTheme<\/code>\u00a0I\u2019ve created three different themes, so there will be three breakpoints with a different ThemeData object based on that breakpoint.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-54ce8cc elementor-widget elementor-widget-code-highlight\" data-id=\"54ce8cc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>class AppBreakpoints {\n  const AppBreakpoints._();\n\n  static const int small = 320;\n  static const int medium = 680;\n  static const int large = 960;\n}\n\nclass ResponsiveApp extends StatelessWidget {\n  const ResponsiveApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return LayoutBuilder(\n      builder: (context, constraints) {\n        late ThemeData themeData;\n\n        if (constraints.maxWidth <= AppBreakpoints.small) {\n          themeData = ResponsiveTheme.small;\n        } else if (constraints.maxWidth <= AppBreakpoints.medium) {\n          themeData = ResponsiveTheme.medium;\n        } else {\n          themeData = ResponsiveTheme.large;\n        }\n\n        return MaterialApp(\n          debugShowCheckedModeBanner: false,\n          theme: themeData,\n          home: const HomeScreen(),\n        );\n      },\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9eaf563 elementor-widget elementor-widget-text-editor\" data-id=\"9eaf563\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 id=\"applying-the-theme-data\">Applying the theme data<\/h2><p>In my\u00a0<code>HomeScreen<\/code>\u00a0widget I will now showcase the power of theme extensions. All widgets have some kind of theming applied to it, either in the global theme, or in-line in this widget. Since the\u00a0<code>ResponsiveApp<\/code>\u00a0returns a different\u00a0<code>ThemeData<\/code>\u00a0object based on the screen resolution it means that the theme extensions will therefore also change their values.<\/p><p>E.g.\u00a0<code>Theme.of(context).extension&lt;AppThemes&gt;()!.spacings.l<\/code>\u00a0returns either\u00a0<code>20.0<\/code>,\u00a0<code>28.0<\/code>\u00a0or\u00a0<code>36.0<\/code>, depending on the theme data.<\/p><p>This means that the font size and the margins\/paddings will change whenever the\u00a0<code>ThemeData<\/code>\u00a0changes in the\u00a0<code>ResponsiveApp<\/code>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-320449b elementor-widget elementor-widget-code-highlight\" data-id=\"320449b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>class HomeScreen extends StatelessWidget {\n  const HomeScreen({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    final spacings = Theme.of(context).extension<AppThemes>()!.appSpacings;\n\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Responsive App'),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            Text(\n              'My responsive app',\n              style: Theme.of(context).textTheme.bodyText1,\n            ),\n            SizedBox(\n              height: spacings.l,\n            ),\n            ElevatedButton(\n              onPressed: () {},\n              child: const Text('Click here!'),\n            )\n          ],\n        ),\n      ),\n    );\n  }\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bc7bc2e elementor-widget elementor-widget-text-editor\" data-id=\"bc7bc2e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2 id=\"lets-see-this-in-action\">Let\u2019s see this in action!<\/h2><p>As you can see the font size, margin and padding changes when the screen resolution changes. Under the hood it is as simple as changing the ThemeData object \ud83d\ude43. Very nice!<\/p><p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/C1xySmb.gif\" \/><\/p><p><strong>Accessing a ThemeExtension in your widgets<\/strong><\/p><p>You might have noticed that accessing the ThemeExtension is a long line of code. Creating an extension on the\u00a0<code>BuildContext<\/code>\u00a0can make our lives easier here \ud83d\ude04<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d63f096 elementor-widget elementor-widget-code-highlight\" data-id=\"d63f096\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>extension ThemeX on BuildContext {\n  AppThemes get _appThemes => Theme.of(this).extension<AppThemes>()!;\n\n  AppSpacings get spacings => _appThemes.appSpacings;\n  AppTextStyles get textStyles => _appThemes.appTextStyles;\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2d9b053 elementor-widget elementor-widget-text-editor\" data-id=\"2d9b053\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Now you can access it directly on the\u00a0<code>BuildContext<\/code>:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5bb0442 elementor-widget elementor-widget-code-highlight\" data-id=\"5bb0442\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-java line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-java\">\n\t\t\t\t\t<xmp>SizedBox(height: context.spacings.l),<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9881d2a elementor-widget elementor-widget-text-editor\" data-id=\"9881d2a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<section class=\"prose post-content\"><h2 id=\"to-conclude\">To conclude<\/h2><p>Even when you don\u2019t need to support different themes (yet), it is a good idea to use the power of\u00a0<code>ThemeExtension<\/code>\u00a0from the start. If in a later stage you find out that you do need to support different screen resolutions, different brands and\/or different color themes, it is much less work to add new theme information and you don\u2019t have to make changes to how the theme is applied.<\/p><p>The possibilities of theme extensions are limitless. You can practically store anything in them and extend your theme any way you like.<\/p><p>You can find the complete source on\u00a0<a href=\"https:\/\/github.com\/egonm12\/flutter-responsive-app\">Github<\/a>.<\/p><\/section><section class=\"prose comments\"><\/section>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and we don\u2019t need to use any third-party package for it! With the release of Flutter 3 we are finally able to extend our ThemeData in an [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":6486,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[149],"tags":[],"class_list":["post-6243","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.4 (Yoast SEO v28.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Responsive design in Flutter, the easy way | Kabisa Software Artisans<\/title>\n<meta name=\"description\" content=\"One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Responsive design in Flutter, the easy way | Kabisa Software Artisans\" \/>\n<meta property=\"og:description\" content=\"One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/\" \/>\n<meta property=\"og:site_name\" content=\"Kabisa Software Artisans\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kabisaict\" \/>\n<meta property=\"article:published_time\" content=\"2022-11-21T13:34:46+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-10-24T10:27:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Egon Meijers\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Egon Meijers\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Responsive design in Flutter, the easy way | Kabisa Software Artisans","description":"One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/","og_locale":"en_US","og_type":"article","og_title":"Responsive design in Flutter, the easy way | Kabisa Software Artisans","og_description":"One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and","og_url":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/","og_site_name":"Kabisa Software Artisans","article_publisher":"https:\/\/www.facebook.com\/kabisaict","article_published_time":"2022-11-21T13:34:46+00:00","article_modified_time":"2023-10-24T10:27:07+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png","type":"image\/png"}],"author":"Egon Meijers","twitter_misc":{"Written by":"Egon Meijers","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#article","isPartOf":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/"},"author":{"name":"Egon Meijers","@id":"https:\/\/kabisa.nl\/en\/#\/schema\/person\/caa3283074e08c8bb46bd93a48eacbad"},"headline":"Responsive design in Flutter, the easy way","datePublished":"2022-11-21T13:34:46+00:00","dateModified":"2023-10-24T10:27:07+00:00","mainEntityOfPage":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/"},"wordCount":840,"commentCount":0,"publisher":{"@id":"https:\/\/kabisa.nl\/en\/#organization"},"image":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#primaryimage"},"thumbnailUrl":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png","articleSection":["Tech blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/","url":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/","name":"Responsive design in Flutter, the easy way | Kabisa Software Artisans","isPartOf":{"@id":"https:\/\/kabisa.nl\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#primaryimage"},"image":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#primaryimage"},"thumbnailUrl":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png","datePublished":"2022-11-21T13:34:46+00:00","dateModified":"2023-10-24T10:27:07+00:00","description":"One of the biggest pains when creating a Flutter app is definitely when you want your app to have a responsive design. But a solution is finally here, and","breadcrumb":{"@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#primaryimage","url":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png","contentUrl":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/11\/Responsive_Design_in_Flutter.png","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/kabisa.nl\/en\/tech\/responsive-design-in-flutter-the-easy-way\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kabisa.nl\/en\/"},{"@type":"ListItem","position":2,"name":"Tech blog","item":"https:\/\/kabisa.nl\/en\/tech\/"},{"@type":"ListItem","position":3,"name":"Responsive design in Flutter, the easy way"}]},{"@type":"WebSite","@id":"https:\/\/kabisa.nl\/en\/#website","url":"https:\/\/kabisa.nl\/en\/","name":"Kabisa Software Artisans","description":"Mission-critical Software for Hightech, Fintech &amp; E-commerce","publisher":{"@id":"https:\/\/kabisa.nl\/en\/#organization"},"alternateName":"Kabisa","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kabisa.nl\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/kabisa.nl\/en\/#organization","name":"Cloud Legends","alternateName":"Kabisa","url":"https:\/\/kabisa.nl\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kabisa.nl\/en\/#\/schema\/logo\/image\/","url":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/12\/kabisa-favicon.png","contentUrl":"https:\/\/kabisa.nl\/wp-content\/uploads\/2022\/12\/kabisa-favicon.png","width":512,"height":512,"caption":"Cloud Legends"},"image":{"@id":"https:\/\/kabisa.nl\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kabisaict","https:\/\/x.com\/kabisasoftware"],"description":"Software Development is onze core-business. Kabisa ontwikkelt innovatieve maatwerk software die naadloos aansluit bij de behoeftes van klanten en eindgebruikers. Dat doen we in nauwe samenwerking in elke fase van het proces: co-creatie noemen we dat.","email":"info@kabisa.nl","telephone":"0495 430 798","legalName":"Kabisa B.V.","foundingDate":"2006-01-01","numberOfEmployees":{"@type":"QuantitativeValue","minValue":"51","maxValue":"200"}},{"@type":"Person","@id":"https:\/\/kabisa.nl\/en\/#\/schema\/person\/caa3283074e08c8bb46bd93a48eacbad","name":"Egon Meijers","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/8991bbaee445b7bd310c8ca2d49cb558e53afcf8e49c40f73484deab98b88153?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/8991bbaee445b7bd310c8ca2d49cb558e53afcf8e49c40f73484deab98b88153?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8991bbaee445b7bd310c8ca2d49cb558e53afcf8e49c40f73484deab98b88153?s=96&d=mm&r=g","caption":"Egon Meijers"}}]}},"_links":{"self":[{"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/posts\/6243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/comments?post=6243"}],"version-history":[{"count":5,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/posts\/6243\/revisions"}],"predecessor-version":[{"id":6249,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/posts\/6243\/revisions\/6249"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/media\/6486"}],"wp:attachment":[{"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/media?parent=6243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/categories?post=6243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kabisa.nl\/en\/wp-json\/wp\/v2\/tags?post=6243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}