Flutter布局方式总(全网最全)

  • Flex 弹性(流式)布局
  • Wrap 包裹,自动换行布局
  • SingleChildScrollView 滚动布局
  • FittedBox 负责对组件进行缩放和位置调整
  • FractionallySizedBox 宽度和高度缩放(百分比布局)
  • ConstrainedBox-限制约束或者LimitedBox(限制宽高)
  • BaseLine 基线的对其方式
  • Row 水平布局
  • Column 垂直布局
  • AspectRatio调整宽高比示例
  • Offstage 控制是否显示
  • OverflowBox溢出父容器显示示例
  • Padding 填充布局
  • Table布局示例
  • Transform矩阵转换示例

1.弹性布局(Flex)

  • 允许子组件按照一定比例来分配父容器空间
  • 主要通过Flex和Expanded来配合实现

① Flex

  • Flex组件可以沿着水平或垂直方向排列子组件
  • direction : Axis.vertical 表示垂直方向 Axis.horizontal 表示水平方向
  • flex : 弹性系数,大于0会按比例来分割,等于0不会扩展占用的空间
效果图

效果图代码

通过 ExpandedFlex实现

import 'package:flutter/material.dart';

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

  final String title;

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

class _FlexWidgetState extends State<FlexWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Flex"),
        ),
        body: Column(
          children: <Widget>[
            Container(
              height: 400.0,
              child: Flex(
                direction: Axis.vertical,
                children: <Widget>[
                  Expanded(
                    flex: 1,
                    child: Container(
                      color: Colors.red,
                    ),
                  ),
                  Expanded(
                    flex: 2,
                    child: Container(
                      color: Colors.yellow,
                    ),
                  ),
                ],
              ),
            ),
            Container(
                height: 120.0,
                child: new Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  // 子组件的排列方式为主轴两端对齐
                  children: <Widget>[
                    Expanded(
                        flex: 2,
                        child: Container(
                          color: Colors.blue,
                        )),
                    Expanded(
                        flex: 1,
                        child: Container(
                          color: Colors.red,
                        ))
                  ],
                ))
          ],
        ));
  }
}

② Wrap

字面意思,包裹📦

  • 把具有相同点的布局整合在一个大的布局组件之内
  • 结局Row布局的局限:在水平位置上“撑破”了屏幕,这种情况可以使用换行处理【Wrap】
  • 常见属性
    • spacing : 水平方向间距
    • runSpacing : 垂直方向间距

效果图

效果图

效果图代码

import 'package:flutter/material.dart';

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

  final String title;

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

class _WrapWidgetState extends State<WrapWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Wrap"),
        ),
        body: Column(
          children: <Widget>[
            Wrap(
              spacing: 4.0,
              runSpacing: 4.0,
              children: <Widget>[
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
                Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
              ],
            )
          ],
        ));
  }
}

案例二

效果图
image.png
代码
Wrap(
        spacing: 8.0, // Chip之间的间距大小
        runSpacing: 4.0, // 行之间的间距大小
        children: <Widget>[
          Chip(
            //添加圆形头像
            avatar: CircleAvatar(
                backgroundColor: Colors.lightGreen.shade800, child: Text('西门', style: TextStyle(fontSize: 10.0),)),
            label: Text('西门吹雪'),
          ),
          Chip(
            avatar: CircleAvatar(
                backgroundColor: Colors.lightBlue.shade700, child: Text('司空', style: TextStyle(fontSize: 10.0),)),
            label: Text('司空摘星'),
          ),
          Chip(
            avatar: CircleAvatar(
                backgroundColor: Colors.orange.shade800, child: Text('婉清', style: TextStyle(fontSize: 10.0),)),
            label: Text('木婉清'),
          ),
          Chip(
            avatar: CircleAvatar(
                backgroundColor: Colors.blue.shade900, child: Text('一郎', style: TextStyle(fontSize: 10.0),)),
            label: Text('萧十一郎'),
          ),
        ],
      )

③SingleChildScrollView-滚动布局

  • 组件是负责滚动的,里面只能嵌套一个组件
  • Column布局超出屏幕后不能滚动,需要在外层嵌套SingleChildScrollView才可以
  • 可以设置滚动方向,也可以通过reverse 属性设置阅读顺序
  • 还可以解决TextField布局溢出问题

④FittedBox 缩放

负责对组件进行缩放和位置调整

  • fit 缩放方式 缩放本身占据FittedBox的大小,默认值BoxFit.contain
    • 子组件的宽度或高度被缩放到父容器限定的值时,就会被停止缩放
  • alignment 对齐方式
 Row(
    children: <Widget>[
      Container(
        color: Colors.blue,
        width: 80.0,
        height: 80.0,
        margin: EdgeInsets.only(bottom: 10.0),
        child: new FittedBox(
          fit: BoxFit.contain,
          alignment: Alignment.topLeft,
          child: new Container(
            color: Colors.yellow,
            child: new Text("FittedBox"),
          ),
        ),
      ),
      Text(
        "BoxFit.contain",
        style: new TextStyle(fontSize: 20.0),
      )
    ],
  )
15730043034089.jpg

⑤FractionallySizedBox 宽度和高度缩放(百分比布局)

  • 基于宽度缩放因子和高度缩放因子来调整布局
  • 大小有可能超出其父组件的设置
  • 如果FractionallySizedBox中子组件设置了大小,则不会起作用,会被覆盖掉
Container(
    color: Colors.blue,
    height: 130.0,
    width: 130.0,
    padding: EdgeInsets.all(5.0),
    child: new FractionallySizedBox(
      alignment: Alignment.topLeft,
      widthFactor: 1.5,//宽度因子
      heightFactor: 0.5,//高度因子
      child: new Container(
        color: Colors.yellow,
      ),
    ),
  )
15730905004805.jpg

⑥ConstrainedBox-限制约束或者LimitedBox(限制宽高)

  • 在其约定范围内,其子组件是不能逾越的
  • ConstrainedBox中主要是constraints起作用,而且这个值不能为null(空)
ConstrainedBox(
    constraints: BoxConstraints(
      minWidth: 100.0,
      minHeight: 100.0,
      maxWidth: 250.0,
      maxHeight: 250.0,
    ),
    child: new Container(
      width: 500.0,
      height: 300.0,
      color: Colors.blue,
      child: Text(
        "100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000",
        style: new TextStyle(color: Colors.black, fontSize: 20.0),
        // 设置省略号
        overflow: TextOverflow.ellipsis,
        // 设置最大行数
        maxLines: 1,
      ),
    ),
  )
15730911486040.jpg

⑦BaseLine

  • 一种基线的对其方式,把不相关的几个组件设置在同一条水平线上进行对齐
  • baseline 设置位置,单位是浮点型(不能为空)
  • baselineType 不能为空
Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[
      new Baseline(
        baseline: 80.0,
        baselineType: TextBaseline.alphabetic,
        child: new Text(
          '今天天气真好',
          style: new TextStyle(
            fontSize: 18.0,
            color: Colors.red,
            textBaseline: TextBaseline.alphabetic,
          ),
        ),
      ),
      new Baseline(
        baseline: 100.0,
        baselineType: TextBaseline.alphabetic,
        child: new Text(
          '适合晨练',
          style: new TextStyle(
            fontSize: 30.0,
            color: Colors.blue,
            textBaseline: TextBaseline.alphabetic,
          ),
        ),
      ),
      new Baseline(
        baseline: 120.0,
        baselineType: TextBaseline.alphabetic,
        child: FlutterLogo(
          size: 100,
        ),
      ),
    ],
  )
效果图

⑧Row 和 Column 水平和纵向布局

  • Column 不支持滚动,想支持滚动,需要考虑使用ListView
  • crossAxisAlignment 子组件在纵轴的对其方式
  • mainAxisAlignment 子组件在水平方向的对其方式
  • textDirection 布局顺序,从左至由,从右至左
  • mainAxisSize max 表示尽可能多地占用水平方向位置,min 则反之

注意

  • 在Row 和 Column 里CrossAxis 和 Main Axis 是不一样的
  • Row 布局 设置 crossAxisAlignment 无效
  • Column 布局 设置 mainAxisAlignment 无效
    效果图

Flex 案例补充

 static var c1 = Container(
    width: 50,
    height: 50,
    color: Colors.blue,
  );
  static var c2 = Container(
    width: 100,
    height: 80,
    color: Colors.red,
  );
  static var c3 = Container(
    width: 150,
    height: 50,
    color: Colors.yellow,
  );

  var flex_test = Flex(
    direction: Axis.horizontal,
    children: <Widget>[
      Expanded(
        child: c1,
      ),
      Expanded(
        child: c2,
      ),
      Expanded(
        child: c3,
      ),
    ],
  );

⑨AspectRatio调整宽高比示例

Container(
        height: 200.0,
        child: AspectRatio(
          aspectRatio: 1.5,//比例可以调整
          child: Container(
            color: Colors.green,
          ),
        ),
      )

Offstage 控制是否显示

//状态控制是否显示文本组件
 bool offstage = true;
Center(
        child: Offstage(
          offstage: offstage,//控制是否显示
          child: Text(
            '我出来啦!',
            style: TextStyle(
              fontSize: 36.0,
            ),
          ),
        ),
      )

OverflowBox溢出父容器显示示例

效果图

image.png

代码

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('OverflowBox溢出父容器显示示例'),
        ),
        body: Container(
          color: Colors.green,
          width: 200.0,
          height: 200.0,
          padding: const EdgeInsets.all(50.0),
          child: OverflowBox(
            alignment: Alignment.topLeft,
            maxWidth: 400.0,
            maxHeight: 400.0,
            child: Container(
              color: Colors.blueGrey,
              width: 300.0,
              height: 300.0,
            ),
          ),
        ));
  }
}

Padding 填充布局

效果图

image.png

代码

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Padding填充布局示例'),
      ),
      body: Center(
        //添加容器 外框
        child: Container(
          width: 300.0,
          height: 300.0,
          //容器内边距上下左右设置为60.0
          padding: EdgeInsets.all(6.0),
          //添加边框
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.green,
              width: 8.0,
            ),
          ),
          //添加容器 内框
          child: Container(
            width: 200.0,
            height: 200.0,
            //添加边框
            decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                color: Colors.blue,
                width: 8.0,
              ),
            ),
            //添加图标
            child: FlutterLogo(),
          ),
        ),
      ),
    );
  }
}

Table布局示例

效果图

image.png

代码

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Table布局示例'),
      ),
      //表格居中
      body: Center(
        //添加表格
        child: Table(
          //设置表格有多少列,并且指定列宽
          columnWidths: const <int, TableColumnWidth>{
            //指定索引及固定列宽
            0: FixedColumnWidth(100.0),
            1: FixedColumnWidth(40.0),
            2: FixedColumnWidth(80.0),
            3: FixedColumnWidth(80.0),
          },
          //设置表格边框样式
          border: TableBorder.all(color: Colors.black38, width: 2.0, style: BorderStyle.solid),
          children: const <TableRow>[
            //添加第一行数据
            TableRow(
              children: <Widget>[
                Text('姓名'),
                Text('性别'),
                Text('年龄'),
                Text('身高'),
              ],
            ),
            //添加第二行数据
            TableRow(
              children: <Widget>[
                Text('张三'),
                Text('男'),
                Text('26'),
                Text('172'),
              ],
            ),
            //添加第三行数据
            TableRow(
              children: <Widget>[
                Text('李四'),
                Text('男'),
                Text('28'),
                Text('178'),
              ],
            ),
          ],
        ),
      ),
    );
  }

Transform矩阵转换示例

效果图
image.png

代码

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Transform矩阵转换示例'),
      ),
      body: Center(
        //父容器 作为背景
        child: Container(
          //背景颜色
          color: Colors.grey,
          //矩阵转换
          child: Transform(
            //对齐方式
            alignment: Alignment.topRight,
            //设置旋转值
            transform: Matrix4.rotationZ(0.3),
            //被旋转容器
            child: Container(
              padding: const EdgeInsets.all(8.0),
              color: const Color(0xFFE8581C),
              child: const Text('Transform矩阵转换'),
            ),
          ),
        ),
      ),
    );
  }
}

补充布局案例

效果图
C0F4CC9F9AEC39877CFB62652C1B5A52.jpg
代码
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //风景区地址部分
    Widget addressContainer = Container(
      padding: const EdgeInsets.all(32.0),//此部分四周间隔一定距离
      //水平布局
      child: Row(
        children: <Widget>[
          Expanded(
            //垂直布局
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start, //次轴即水平方向左侧对齐
              children: <Widget>[
                Container(
                  padding: const EdgeInsets.only(bottom: 8.0),//与下面文本间隔一定距离
                  child: Text(
                    '风景区地址',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                Text(
                  '湖北省十堰市丹江口市',
                  style: TextStyle(
                    color: Colors.grey[500],
                  ),
                ),
              ],
            ),
          ),
          //图标
          Icon(
            Icons.star,
            color: Colors.red[500],
          ),
          Text('66'),
        ],
      ),
    );

    //构建按钮组中单个按钮 参数为图标及文本
    Column buildButtonColumn(IconData icon, String label) {
      //垂直布局
      return Column(
        mainAxisSize: MainAxisSize.min,//垂直方向大小最小化
        mainAxisAlignment: MainAxisAlignment.center,//垂直方向居中对齐
        children: <Widget>[
          Icon(icon, color: Colors.lightGreen[600]),//上面图标部分
          Container(
            //距离上面图标一定间距
            margin: const EdgeInsets.only(top: 8.0),
            //下面文本部分
            child: Text(
              label,
              style: TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: Colors.lightGreen[600],
              ),
            ),
          )
        ],
      );
    }

    //按钮组部分
    Widget buttonsContainer = Container(
      //水平布局
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,//水平方向均匀排列每个元素
        children: <Widget>[
          buildButtonColumn(Icons.call, '电话'),
          buildButtonColumn(Icons.near_me, '导航'),
          buildButtonColumn(Icons.share, '分享'),
        ],
      ),
    );

    //风景区介绍文本部分
    Widget textContainer = Container(
      //设置上下左右内边距
      padding: const EdgeInsets.all(32.0),
      //文本块一定是用'''来引用起来
      child: Text(
        '''
        武当山,中国道教圣地,又名太和山、谢罗山、参上山、仙室山,古有“太岳”、“玄岳”、“大岳”之称。位于湖北西北部十堰市丹江口市境内。东接闻名古城襄阳市,西靠车城十堰市 ,南望原始森林神农架,北临高峡平湖 丹江口水库。
        明代,武当山被皇帝封为“大岳”、“治世玄岳”,被尊为“皇室家庙”。武当山以“四大名山皆拱揖,五方仙岳共朝宗”的“五岳之冠”地位闻名于世。
        1994年12月,武当山古建筑群入选《世界遗产名录》,2006年被整体列为“全国重点文物保护单位” 。2007年,武当山和长城、丽江、周庄等景区一起入选 “欧洲人最喜爱的中国十大景区”。2010至2013年,武当山分别被评为国家5A级旅游区、国家森林公园、中国十大避暑名山、海峡两岸交流基地,入选最美 “国家地质公园”。 
        截至2013年,武当山有古建筑53处,建筑面积2.7万平方米,建筑遗址9处,占地面积20多万平方米,全山保存各类文物5035件。 
        武当山是道教名山和武当武术的发源地,被称为“亘古无双胜境,天下第一仙山”。武当武术,是中华武术的重要流派。元末明初,道士张三丰集其大成,开创武当派。
        ''',
        softWrap: true,
      ),
    );

    return MaterialApp(
      title: '布局综合示例',
      //自定义主题,主体颜色为绿色风格
      theme: ThemeData(
        brightness: Brightness.light, //应用程序整体主题的亮度
        primaryColor: Colors.lightGreen[600], //App主要部分的背景色
        accentColor: Colors.orange[600], //前景色(文本、按钮等)
      ),
      home: Scaffold(
        appBar: AppBar(
          //页面标题
          title: Text(
            '武当山风景区',
            style: TextStyle(color: Colors.white),
          ),
        ),
        //使用列表视图默认为垂直布局,并且子元素能够上下滚动
        body: ListView(
          children: <Widget>[
            //风景图片
            Image.asset(
              'images/wudang.jpeg',
              width: 600.0,
              height: 240.0,
              fit: BoxFit.cover, //图片填充整个父容器
            ),
            addressContainer,
            buttonsContainer,
            textContainer,
          ],
        ),
      ),
    );
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266