Flutter开发实战:页面布局详解

本篇博客Demo下载点击这里:Flutter布局Demo

1. Flutter布局实战讲解

1.1 布局坐标

首先新建一个Flutter项目 我这里命名为flutter_layoutdemo,

image.png

接下来我们创建一个用来练习布局的layout_demo.dart文件,直接按快捷键“Command + N”
image.png

然后找到main.dart里面的MyApp类,替换掉系统默认的代码,如下图所示:
image.png

替换掉之后,我们直接按快捷键“Control+R” 编译运行到模拟器上面,可以选择安卓或者iOS模拟器,也可以选择运行在真机上面,如下图选择你想运行的模拟器:
image.png

这里我选择的是iphone 11 模拟器,运行结果如下:
image.png

接下来我们在layoutDemo类的build方法里面加入一些小部件

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: Center(
        child: Text('kongyulu'),
      ),
    );
  }
}

"Control + R " 编译运行

image.png

其实我们还可以通过alignment 属性是布局居中显示,这个类似于IOS 的UILabel的对齐属性。这样我们可以修改代码如下:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Text('kongyulu2')
    );
  }

我们热更新一下,可以看到效果如下:


image.png

下面我们简单介绍一下aligment属性:
实际上我们上面代码用的相对布局,坐标原点在中心,我们aligment属性 Alignment(x,y)传入x,y的坐标,这里传入(0,0)标识在中心位置,如下图所示:


image.png

如上图所示,Alignment(-1,-1)标识在左上角,Alignment(1,1)在右下角,Alignment(-1,1)在左下角,Alignment(1,-1)在右上角,下面我们可以简单验证一下

如果我们把alignment属性改为Alignment(1,0),效果如下:


image.png

如果我们把alignment属性改为Alignment(0,1),效果如下:


image.png

如果我们把alignment属性改为Alignment(-1,-1),效果如下:
image.png

由此我们可以知道(-1,-1)在左上角, (1,1)在右上角,

1.2 横向布局Row

接下来我们讲解一下横向布局Row,我们修改一下代码,增加一个Row布局,代码如下:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Row(
        children: <Widget>[
          Icon(Icons.add),
          Icon(Icons.access_alarm),
          Icon(Icons.account_balance_wallet),
        ],
      )
    );
  }
}

热更新一下,效果如下:


image.png

Row表示横向布局,里面需要传入一个Widget数组,数组里面的Widget小部件都横向排列。我们可以看到小部件默认有点小,我们来修改一下大小将size改为80

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Row(
        children: <Widget>[
          Icon(Icons.add,size: 80,),
          Icon(Icons.access_alarm,size: 80,),
          Icon(Icons.account_balance_wallet,size: 80,),
        ],
      )
    );
  }
}

重新运行一下效果如下:


image.png

如果我们想跟里面的小部件添加背景颜色,我们只需要将这个小部件放到一个新的Container容器里面包装一下,即可使用Container里面的相关属性,设置颜色等属性。
我们再修改一下代码,给小部件添加背景颜色:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Row(
        children: <Widget>[
          Container(child:Icon(Icons.add,size: 80,) ,color: Colors.blue,)
          ,
          Container(child:Icon(Icons.access_alarm,size: 80,) ,color: Colors.yellow,)
          ,
          Container(child:Icon(Icons.account_balance_wallet,size: 80,) ,color: Colors.green,)
          ,

        ],
      )
    );
  }
}

重新运行一下效果如下:


image.png

1.3 纵向布局Column

纵向布局时垂直方向的布局,更横向布局相对应。我们只需要将上面的横向布局代码的Row改为Column,如下:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Column(
        children: <Widget>[
          Container(child:Icon(Icons.add,size: 80,) ,color: Colors.blue,)
          ,
          Container(child:Icon(Icons.access_alarm,size: 80,) ,color: Colors.yellow,)
          ,
          Container(child:Icon(Icons.account_balance_wallet,size: 80,) ,color: Colors.green,)
          ,

        ],
      )
    );
  }
}

热更新一下,我们来看一下效果:


image.png

1.4 层级布局Stack

我们再将上面的代码修改为Stack层级布局看看什么效果,修改代码如下:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      alignment: Alignment(0.0, 0.0),
      child: Stack(
        children: <Widget>[
          Container(child:Icon(Icons.add,size: 80,) ,color: Colors.blue,)
          ,
          Container(child:Icon(Icons.access_alarm,size: 80,) ,color: Colors.yellow,)
          ,
          Container(child:Icon(Icons.account_balance_wallet,size: 80,) ,color: Colors.green,)
          ,

        ],
      )
    );
  }
}

我们快捷键“Command+||” 热更新一下,运行效果如下:


image.png

本来是三个,我们只看到了最后一个小部件,说明另外两个被遮挡了,我们来修改一下每个小部件的大小:


image.png

由此我们可以知道 Row横向布局对应x轴,Column纵向布局对应y轴,Stack层次布局对应z轴,我们由x,y,z可以很容易布局想要的效果。

1.5 主轴 mainAxisAlignment

我们的Row,Column都有两个非常重要的属性:主轴mainAxisAlignment 和 交叉轴

其中主轴需要传入一个对象,我们查看源码可以看到:

image.png

主轴属性传入一个MainAxisAlignment对象,我们可以看到它有下面结构属性:
image.png

  • MainAxisAlignment.center: 表示沿着主轴方向居中显示,如果Row横向布局,则是沿着x轴从左到右横着居中排列显示,如果是Column纵向布局,则是沿着y轴从上往下,纵向居中显示
    image.png

    image.png
  • MainAxisAlignment.end:
    如果Row横向布局,则是沿着x轴从左到右横着居中,靠右对齐排列显示
    image.png

    如果是Column纵向布局,则是沿着y轴从上往下,纵向居中, 并且靠底部对齐显示
    image.png
  • MainAxisAlignment.spaceAround: 就是将主轴方向剩下的空间平均分配给每个子控件。
    如果Row横向布局,则水平方向剩下的空间平均分配在每个空间的周围
    image.png

    如果是Column纵向布局,则垂直方向剩下的空间平均分配在每个空间的周围
    image.png

    image.png
  • MainAxisAlignment.spaceBetween: 剩下的空间平均分配到每个小部件之间的间隔。
    image.png

    image.png
  • MainAxisAlignment.spaceEvently: 剩下空间和小部件一起平均分配,是等间距的分配。
    image.png

    image.png
  • MainAxisAlignment.start : 表示主轴开始的方向, 也是默认值
    如果是Row布局,MainAxisAlignment.start 主轴效果如下:
    image.png

    如果是Column布局,MainAxisAlignment.start 主轴效果如下:
    image.png

1.6 交叉轴 CrossAxisAlignment

CrossAxisAlignment交叉轴拥有的属性如下:

image.png

交叉轴默认的属性是center 居中显示

  • CrossAxisAlignment.baseline :
    这个baseline属性不能单独使用,需要结合其他属性配合使用,否则会报错:
    image.png

    我们修改一下代码,增加textBaseline: TextBaseline.alphabetic属性,配合使用,因为baseline属性需要针对文本才能体现效果,所以我们还需要在每个小部件里面增加一个文本标签

主轴为x轴,沿交叉轴y轴方向底部对齐

image.png

我们将标签的背景大小设置一致更好对比:
image.png

纵向布局时,baseline属性使字体沿交叉轴左对齐
image.png

我们再来看一下去掉baseline属性的效果:
image.png

  • CrossAxisAlignment.center :
    image.png

    image.png
  • CrossAxisAlignment.end :
    image.png

    image.png
  • CrossAxisAlignment.start :
    image.png

    image.png
  • CrossAxisAlignment.stretch :
    image.png

    image.png

1.7 Expanded自动填充

Expanded 是一种比较灵活的布局方案,它使得子部件随之父控件的大小自动填充

我们接下来将上面的代码修改一下,将每个小部件放入Expanded布局中,修改后代码如下:

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      alignment: Alignment(0.0, 0.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        crossAxisAlignment: CrossAxisAlignment.baseline,
        textBaseline: TextBaseline.alphabetic,
        children: <Widget>[
          Expanded(child: Container(child:Text('孔雨露',style: TextStyle(fontSize: 15),) ,color: Colors.blue,height: 80,),)
          ,
          Expanded(child:Container(child:Text('努力',style: TextStyle(fontSize: 30),) ,color: Colors.yellow,height: 80,),)
          ,
          Expanded(child: Container(child:Text('坚持',style: TextStyle(fontSize: 60),) ,color: Colors.green,height: 80,),)
          ,

        ],
      )
    );
  }
}

运行效果如下:

image.png

我们将上面的代码的布局Column改为Row横向布局,效果如下:
image.png

由此我们知道,如果我们设置了Expanded自动填充,假设我们使用Row横向布局我们不需要设置宽度(就算设置了宽度也不会生效,没有意义),沿主轴x轴每个子部件自动填充拉伸满,不会在主轴方向留下空隙,同理,如果是纵向布局,则设置Expanded自动填充后,不需要设置高度(就算设置了高度也不会生效,没有意义),沿主轴y会自动填充拉伸。

这个属性对应我们文字很长时,会根据宽度自动换行,如下图:


image.png

接下来,如果我们看一下如果上面的三个小部件,不是每个都使用expanded布局呢,现在我们改一下代码,把中间的那个小部件改为不是expanded布局。


image.png

1.8 Alignment属性

我们将上面的代码简化一下,改为如下:

  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      alignment: Alignment(0.0, 0.0),
      child: Container(child:
      Icon(Icons.add,size: 30,),height: 40,
        color:Colors.blue,)
    );
  }

运行效果如下:

image.png

我们一般用alignment根据比例来显示位置,
收录自|原文地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容