Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A complete guide on creating responsive apps using Fluter.

License

NotificationsYou must be signed in to change notification settings

MarsGoatz/flutter-responsive-apps-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NOTE: Everything in this repo falls under the GPL 3 license EXCEPT THE IMAGES IN README! This is becaue of the tool used to create them.

1.1. Box Contraints

Flutter framework is constraint based framework, i.e, a widget bounds is constrained by the parent widget. If, for example, you have a container has a dimension of height 900px and width 500px but when you run the code on your simulator, you see that its actually smaller than what you have intended to, this is due to the box constraints coming in from the parent widget which passes contraints of maybe 800px 400px. If the parent of the container is a scaffold, then the box constraint coming in from the scaffold to the container would be the screen dimensions. Box contraints are passed automatically by the parent.

alt Box Constraint Image


Example 1 - Scaffold -> Container

import'package:flutter/material.dart';import'package:flutter/widgets.dart';classExample1extendsStatelessWidget {constExample1({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {//Scaffold passes down screen dimensions as constraintsreturnScaffold(      appBar:AppBar(        title:Text('Example 1'),      ),      body:Container(        color:Colors.green,        width:double.infinity,        height:double.infinity,      ),    );  }}

Example 2 - Scaffold -> Container 1 -> Container 2

import'package:flutter/material.dart';import'package:flutter/widgets.dart';classExample2extendsStatelessWidget {constExample1({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {//Scaffold passes down screen dimensions as constraintsreturnScaffold(      appBar:AppBar(        title:Text('Example 1'),      ),      body:Container(        width:200,        height:200,        child:Container(          color:Colors.green,          width:double.infinity,          height:double.infinity,        ),      ),    );  }}


"A widget can decide its own size only within the constraints given to it by its parent. This means a widget usually can’t have any size it wants."

Notes:

  • A parent can pass inifinity constraints to its child
  • Use ConstrainedBox to pass constraints to child in your custom widgets
  • You can check the constraints coming from parent from dev tools for debugging.

Additional Reading:

1.2. Responsiveness on Mobile Screens

When creating an app across various mobile screen, we want to make sure they are responsive and expand or collapse based on the screen dimensions. So we will look at how to achieve that with Columns and Rows.

alt Column & Row Main Axis


1.2.1. Columns

So, Columns, unlike Scaffold or Container don't pass constraint along the main axis and will build the height from the children. This is because Columns children are dynamic.

Example 1 - Unresponsive Overflow

import'package:flutter/material.dart';import'package:flutter/widgets.dart';classColumnExample1extendsStatelessWidget {constColumnExample1({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {returnScaffold(      appBar:AppBar(        title:Text('Example 1'),      ),//if the containers height are infite here, the app will //crash      body:Column(        children: [Container(            color:Colors.green,            height:100,          ),Container(            color:Colors.blue,            height:300,          ),Container(            color:Colors.orange,            height:1000,          ),        ],      ),    );  }}

As you saw with the example, the overflow error generally happens with Columns and Rows because they don't pass constraint to the children along the main axis to restric the child's height.

Example 2 - Unresponsive Unused Space

import'package:flutter/material.dart';import'package:flutter/widgets.dart';classColumnExample1extendsStatelessWidget {constColumnExample1({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {returnScaffold(      appBar:AppBar(        title:Text('Example 1'),      ),//if the containers height are infite here, the app will //crash      body:Column(        children: [Container(            color:Colors.green,            height:100,          ),Container(            color:Colors.blue,            height:300,          ),Container(            color:Colors.orange,            height:100,          ),        ],      ),    );  }}

Here, there is unused space. The dimensions could work for one mobile device but not for others asdifferent mobile devices have different heights.

So how do we solve the problem of widgets going out of bounds? We use a special widget calledExpanded orFlexible. These widgets can only be used by Columns or Rows.

Expanded will fill the remaining space with the child widget, which in our case is the orange widget. Note that when using Expanded, it will completely ignore the child's height.

Example - Responsive With Expanded

import'package:flutter/material.dart';import'package:flutter/widgets.dart';classColumnExampleResponsiveextendsStatelessWidget {constColumnExampleResponsive({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {returnScaffold(      appBar:AppBar(        title:Text('Example 1'),      ),      body:Column(        children: [Container(            color:Colors.green,            height:100,          ),Container(            color:Colors.blue,            height:300,          ),Expanded(            child:Container(              color:Colors.orange,              height:500,            ),          ),        ],      ),    );  }}

Notes:

  • Rows is pretty similar to Column, except that the main axis is controlled by width.
  • Use Flex widget if you want dynamic control, i.e, switch between Column and Row.
  • Flexible is similar toExpanded but with more options on the Columns on how children should take up space.
  • Useflex attribute with Expanded to more fine grained control of the space taken by children

Additional Reading:

1.2.2. Handling Orientation

alt Column & Row Main Axis


Notes:

  • Use OrientationBuilder to know what the current orientation and return the respective widget
  • Disable particular orientation

Additional Reading:

1.3. Handling Wider Screens

So for handling different mobile device screen, using Columns/Rows with Expanded is sufficient but toexpand the repsonsiveness to wider screens like desktop apps and desktop browsers, we have to rely oneither MediaQuery or LayoutBuilder.

alt Column & Row Main Axis


1.3.1. Layout Builder

Layout builder is similar to MediaQuery when it comes to screen sizes but it can used with any widgetand get the parent constraints.

Layout Builder Orientation Example

import'package:flutter/material.dart';import'package:flutter/widgets.dart';import'../responsive_util.dart';classLayoutBuilderResponsiveextendsStatelessWidget {constLayoutBuilderResponsive({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {returnScaffold(      appBar:ResponsiveUtil.isWideScreen(context)?null:AppBar(              title:Text('LayoutBuilder Responsive'),            ),      body:LayoutBuilder(        builder: (context, constraints) {returnGridView.count(            crossAxisCount: constraints.maxWidth<500?2:4,            children:List.generate(100, (index) {returnContainer(                child:Center(                  child:Image.network('https://picsum.photos/id/${index +400}/${constraints.maxWidth <500 ? (constraints.maxWidth /2).round() : (constraints.maxWidth /4).round()}',                    loadingBuilder: (BuildContext context,Widget child,ImageChunkEvent loadingProgress) {if (loadingProgress==null)return child;returnCenter(                        child:CircularProgressIndicator(),                      );                    },                  ),                ),              );            }),          );        },      ),    );  }}

1.3.2. MediaQuery

Using MediaQuery, you can get information like screen dimensions, accessibilty information which you can use to handle various screen sizes.

Media Query Example Handling Orientation

import'package:flutter/material.dart';import'package:flutter/widgets.dart';import'../responsive_util.dart';classMediaQueryResponsiveextendsStatelessWidget {constMediaQueryResponsive({Key key}):super(key: key);@overrideWidgetbuild(BuildContext context) {returnScaffold(        appBar:ResponsiveUtil.isWideScreen(context)?null:AppBar(                title:Text('MediaQuery Responsive'),              ),        body:GridView.count(          crossAxisCount:MediaQuery.of(context).size.width<500?2:4,          children:List.generate(100, (index) {returnContainer(              child:Center(                child:Image.network('https://picsum.photos/id/${index +100}/${MediaQuery.of(context).size.width <500 ? (MediaQuery.of(context).size.width /2).round() : (MediaQuery.of(context).size.width /4).round()}',                  loadingBuilder: (BuildContext context,Widget child,ImageChunkEvent loadingProgress) {if (loadingProgress==null)return child;returnCenter(                      child:CircularProgressIndicator(),                    );                  },                ),              ),            );          }),        ));  }}

Media Query Example Handling Companion App

classResponsiveUtil {staticfinal kBreakPoint=800;staticboolisWideScreen(BuildContext context) {returnMediaQuery.of(context).size.width> kBreakPoint;  }}classMyHomePageextendsStatefulWidget {MyHomePage({Key key,this.title}):super(key: key);finalString title;@override_MyHomePageStatecreateState()=>_MyHomePageState();}class_MyHomePageStateextendsState<MyHomePage> {PageController _controller=PageController(    initialPage:0,  );@overridevoiddispose() {    _controller.dispose();super.dispose();  }@overrideWidgetbuild(BuildContext context) {returnScaffold(      appBar:AppBar(        title:Text(widget.title),      ),      body:ResponsiveUtil.isWideScreen(context)?SafeArea(              child:Row(                children: [Container(                    width:MediaQuery.of(context).size.width* .30,                    child:ListView(                      children: [ListTile(                          title:Center(                            child:Text('OPTIONS'),                          ),                        ),Divider(                          color:Colors.orange,                        ),ListTileCustomWideScreen(                            title:'Box Constraint Examples',                            onTap: ()=> _controller.page==0?null: _controller.animateToPage(0,                                    duration:Duration(milliseconds:500),                                    curve:Curves.fastLinearToSlowEaseIn)),Divider(                          color:Colors.white,                        ),ListTileCustomWideScreen(                            title:'Columns & Rows',                            onTap: ()=> _controller.page==1?null: _controller.animateToPage(1,                                    duration:Duration(milliseconds:500),                                    curve:Curves.fastLinearToSlowEaseIn)),Divider(                          color:Colors.white,                        ),ListTileCustomWideScreen(                            title:'Media Query',                            onTap: ()=> _controller.page==2?null: _controller.animateToPage(2,                                    duration:Duration(milliseconds:500),                                    curve:Curves.fastLinearToSlowEaseIn)),Divider(                          color:Colors.white,                        ),ListTileCustomWideScreen(                            title:'Layout Builder',                            onTap: ()=> _controller.page==3?null: _controller.animateToPage(3,                                    duration:Duration(milliseconds:500),                                    curve:Curves.fastLinearToSlowEaseIn)),Divider(                          color:Colors.white,                        )                      ],                    ),                  ),VerticalDivider(                    color:Colors.grey,                    indent:0,                    endIndent:0,                    thickness:1,                    width:0.5,                  ),Expanded(                      child:PageView(                    physics:NeverScrollableScrollPhysics(),                    pageSnapping:false,                    controller: _controller,                    children: [BoxContraintExamples(),ColumnExamples(),MediaQueryResponsive(),LayoutBuilderResponsive()                    ],                  ))                ],              ),            ):SafeArea(              child:ListView(                children: [ListTileCustom(                      title:'Box Constraint Examples',                      screen:BoxContraintExamples()),Divider(                    color:Colors.white,                  ),ListTileCustom(                      title:'Columns & Rows', screen:ColumnExamples()),Divider(                    color:Colors.white,                  ),ListTileCustom(                      title:'Mobile Screen Orientation',                      screen:OrientationExamples()),Divider(                    color:Colors.white,                  ),ListTileCustom(                      title:'Media Query', screen:MediaQueryResponsive()),Divider(                    color:Colors.white,                  ),ListTileCustom(                      title:'Layout Builder',                      screen:LayoutBuilderResponsive()),Divider(                    color:Colors.white,                  )                ],              ),            ),    );  }}

Notes:

  • For fine grained control per widget on how it should be repsonsive, use LayoutBuilder
  • MediaQuery also provides information related to accessibility and you can make changes to font size etc

Additional Reading:

About

A complete guide on creating responsive apps using Fluter.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp