Flutter基礎(chǔ)控件篇[2]--布局

前言

接著Flutter基礎(chǔ)控件篇[1],這一篇主要記錄Flutter容器控件的使用,也就是常用的布局控件(Layout)。

在學(xué)習(xí)的過程中,除了官方文檔之外,還參考了不少其他的博客資料,發(fā)現(xiàn)有挺多文章在一些細(xì)節(jié)問題上其實(shí)并沒有說明白,甚至有的實(shí)測(cè)之后證實(shí)是錯(cuò)的,有的屬性的解釋像是谷歌翻譯了一下直接就貼過來,實(shí)際含義其實(shí)都沒有說清楚,然后還被多處轉(zhuǎn)載粘貼,一處錯(cuò)誤可以在好些篇文章里同樣出現(xiàn)。
用心實(shí)在的好資料還是少數(shù)啊!
這里筆記中的內(nèi)容不一定全都對(duì),可能有遺漏或者實(shí)測(cè)場(chǎng)景不夠全面,在復(fù)雜特殊的某些場(chǎng)景可能有不符合的結(jié)果,但是里面所有內(nèi)容都是經(jīng)過代碼驗(yàn)證根據(jù)實(shí)際結(jié)果總結(jié)來的,也沒有類似機(jī)器翻譯的內(nèi)容在里面讓人看完模棱兩可啥也沒明白跟沒看一樣。沒理解的東西不往上記,沒驗(yàn)證的東西不往上記,盡量保證以后回頭來看,不會(huì)坑到自己。

正文

下面是幾個(gè)常用的容器布局控件:

Container

容器控件,可以添加一個(gè)子控件,設(shè)置寬度高度,padding,margin,背景顏色,背景裝飾等屬性,基本包含了容器控件的常用基本屬性。
基本使用:

Widget build(BuildContext context) {
    return Container(
        width: 200.0,
        height: 150.0,
        margin: EdgeInsets.fromLTRB(25, 15, 0, 0),
        padding: EdgeInsets.fromLTRB(10, 15, 10, 15),
        alignment: Alignment(0, 0),
        decoration: BoxDecoration(boxShadow: [
          //卡片陰影
          BoxShadow(
              color: Colors.black54,
              offset: Offset(5.0, 5.0),
              blurRadius: 7.0)
        ]),
        child: Image.network(
          Consts.imgUrl,
          width: 200.0,
          height: 150.0,
        ));
  }

常用屬性:
width:寬度,如果設(shè)置具體值則為具體值,不設(shè)置則包裹子控件大小,設(shè)置為double.infinity一般會(huì)充滿父控件或者充滿屏幕(如果沒有其他特別的約束條件);
height:高度,使用方法基本同width;
margin:設(shè)置控件與其他控件的外邊距;
padding:設(shè)置內(nèi)邊距;
decoration:背景裝飾;
alignment:設(shè)置子控件的方位,用Alignment屬性值來表示,具體對(duì)應(yīng)的方位如下:

  • Alignment topLeft = Alignment(-1.0, -1.0);
  • Alignment topCenter = Alignment(0.0, -1.0);
  • Alignment topRight = Alignment(1.0, -1.0);
  • Alignment centerLeft = Alignment(-1.0, 0.0);
  • Alignment center = Alignment(0.0, 0.0);
  • Alignment centerRight = Alignment(1.0, 0.0);
  • Alignment bottomLeft = Alignment(-1.0, 1.0);
  • Alignment bottomCenter = Alignment(0.0, 1.0);
  • Alignment bottomRight = Alignment(1.0, 1.0);
Row(橫向布局)、Column(縱向布局)

類似Android中的LinearLayout,只是拆分開來,一個(gè)橫向排列,一個(gè)縱向排列,它倆布局除了方向不同之外,其他的屬性基本含義都一樣:
基本用法:

Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.max,//主軸方向(縱向)占空間盡量大,(如果沒有其他特別的約束條件則要么填滿屏幕,要么填滿父布局)
      verticalDirection: VerticalDirection.down,//控件順序正常順序,VerticalDirection.up則倒敘
      crossAxisAlignment: CrossAxisAlignment.center,//縱軸方向上控件排列規(guī)則(居中 靠邊等)
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,//主軸方向上控件排列規(guī)則(居中 靠邊 均勻分布等)
      textBaseline: TextBaseline.alphabetic,
      children: <Widget>[
        Text('verticalDirection:VerticalDirection.up'),
        Text('crossAxisAlignment: CrossAxisAlignment.center'),
        Text('mainAxisAlignment: MainAxisAlignment.spaceEvenly'),
        Text('textBaseline: TextBaseline.ideographic'),
      ],
    );
  }
Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.max,//主軸方向(橫向)占空間盡量大,(如果沒有其他特別的約束條件則要么填滿屏幕,要么填滿父布局)
      verticalDirection: VerticalDirection.up,//實(shí)測(cè) up和down效果一樣,好像沒生效。
      crossAxisAlignment: CrossAxisAlignment.center,//縱軸方向(縱向)上控件排列規(guī)則(居中 靠邊等)
      mainAxisAlignment: MainAxisAlignment.spaceAround,////主軸方向上控件排列規(guī)則(居中 靠邊 均勻分布等)
      textBaseline: TextBaseline.ideographic,
      textDirection: TextDirection.rtl,//從左到右排列
      children: <Widget>[
        Container(
          color: Colors.blue[100],
          width: 70,
          height: 70,
        ),
        Container(color: Colors.blue[200], width: 70, height: 70),
        Container(color: Colors.blue[300], width: 70, height: 70),
        Container(color: Colors.blue[400], width: 70, height: 70),
      ],
    );
  }

這里mainAxis和crossAxis代表主軸方向和縱軸方向,Row(橫向布局)主軸方向就是橫向,縱軸方向就是縱向;Column(縱向布局)主軸方向就是縱向,縱軸方向就是橫向;
幾個(gè)常用屬性:
mainAxisSize:

  • MainAxisSize.max:主軸方向占空間盡量大,(如果沒有其他特別的約束條件則要么填滿屏幕,要么填滿父布局);
  • MainAxisSize.min:主軸方向占空間盡量小,基本就是包裹子控件的尺寸了

textDirection

  • TextDirection.ltr,從左到右排列;
  • TextDirection.rtl,從右到左排列;

textBaseline

  • TextBaseline.alphabetic,使用按照排列字母字符的基準(zhǔn)線排列方式
  • TextBaseline.ideographic,使用按照表意字字符的基準(zhǔn)線排列方式(比如中文);

表意字好像是說可以拆解結(jié)構(gòu)的文字類型,通過各種部首的組合可以形成各種文字,例如中文。(這里有一個(gè)視頻,簡單了解什么是表意字)

verticalDirection

  • VerticalDirection.up,從下向上排列;
  • VerticalDirection.down,從上向下排列;

mainAxisAlignment:

  • start:將children放置在主軸的起點(diǎn);
  • center:將children放置在主軸的中心;
  • end:將children放置在主軸的末尾;
  • spaceAround:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,但是首尾child的空白區(qū)域?yàn)?/2;
  • spaceBetween:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,首尾child都靠近首尾,沒有間隙;
  • spaceEvenly:將主軸方向上的空白區(qū)域均分,使得children之間的空白區(qū)域相等,包括首尾child;

crossAxisAlignment:

  • start:將children放置在縱軸的起點(diǎn);
  • center:將children放置在縱軸的中心;
  • end:將children放置在縱軸的末尾;
Wrap 流式布局

Wrap包裹子控件,也可以設(shè)置橫向和縱向,它與Row和Column的區(qū)別在于:Row和Column只有一行或一列,子控件尺寸超出了就會(huì)顯示不全,但是Wrap會(huì)自動(dòng)換行。

Widget build(BuildContext context) {
    return Wrap(
      direction: Axis.horizontal,
      //start end值受textDirection具體值的影響
      alignment: WrapAlignment.start,
      crossAxisAlignment: WrapCrossAlignment.end,//好像是runAlignment生效了 crossAxisAlignment沒有生效
      runAlignment: WrapAlignment.center,//縱軸方向?qū)R方式
      spacing: 15,//主軸方向間距15
      runSpacing: 10,//縱軸方向間距10
      textDirection: TextDirection.ltr,
      children: <Widget>[
        Container(color: Colors.green[100], width: 70, height: 70,),
        Container(color: Colors.green[200], width: 70, height: 70),
        Container(color: Colors.green[300], width: 70, height: 70),
        Container(color: Colors.green[400], width: 70, height: 70),
        Container(color: Colors.green[100], width: 70, height: 70,),
        Container(color: Colors.green[200], width: 70, height: 70),
        Container(color: Colors.green[300], width: 70, height: 70),
        Container(color: Colors.green[400], width: 70, height: 70),
      ],
    );
  }

常用屬性:
direction:排列方向

  • Axis.horizontal 橫向布局(主軸為橫向)
  • Axis.vertical 縱向布局(主軸為縱向)

alignment:使用WrapAlignment的屬性值,但是含義和Row、Column基本一致;
spacing:主軸方向子控件間距;
runSpacing:縱軸方向的間距(主軸是橫向則縱軸是縱向,主軸是縱向則縱軸是橫向);
runAlignment:縱軸方向的對(duì)齊方式;

這里有個(gè)疑惑,crossAxisAlignment和runAlignment都表示縱軸方式的對(duì)齊方式,實(shí)測(cè)的結(jié)果似乎crossAxisAlignment并沒有起作用,只有runAlignment起作用了,這個(gè)還有待進(jìn)一步考證。

Stack 重疊布局

可以把子控件疊在一起來展示。Stack可以搭配Positioned控件一起使用,Positioned控件可以控制子控件在Stack中的具體位置(設(shè)置距離左上右下的具體參數(shù))和控件大小(設(shè)置寬高),使用場(chǎng)景會(huì)非常多。

Widget build(BuildContext context) {
    return Stack(
      fit:StackFit.loose,
      alignment: AlignmentDirectional.center,
      textDirection: TextDirection.ltr,
      overflow: Overflow.clip,
      children: <Widget>[
        Container(width: 120,height: 120,color: Colors.cyan[200],),
        Container(width: 90,height: 90,color: Colors.cyan[400],),
        Container(width: 60,height: 60,color: Colors.cyan[600],),
        Positioned(left: 100,top: 100,child: Container(width: 120,height: 120,color: Colors.cyan[800],),)//指定位置,超出stack范圍,測(cè)試overflow屬性
      ],
    );
  }

常用屬性:
alignment:設(shè)置子控件的方位,用AlignmentDirectional的值來表示,這個(gè)類里面的start和end受textDirection具體值的影響,TextDirection.ltr(左到右)對(duì)應(yīng)start為左邊,,TextDirection.rtl(右到左)對(duì)應(yīng)start為右邊,屬性值具體對(duì)應(yīng)的方位如下

  • AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0);
  • AlignmentDirectional topCenter = AlignmentDirectional(0.0, -1.0);
  • AlignmentDirectional topEnd = AlignmentDirectional(1.0, -1.0);
  • AlignmentDirectional centerStart = AlignmentDirectional(-1.0, 0.0);
  • AlignmentDirectional center = AlignmentDirectional(0.0, 0.0);
  • AlignmentDirectional centerEnd = AlignmentDirectional(1.0, 0.0);
  • AlignmentDirectional bottomStart = AlignmentDirectional(-1.0, 1.0);
  • AlignmentDirectional bottomCenter = AlignmentDirectional(0.0, 1.0);
  • AlignmentDirectional bottomEnd = AlignmentDirectional(1.0, 1.0);

overflow:

  • Overflow.clip 當(dāng)子控件超出Stack的顯示范圍時(shí),截掉超出范圍的部分不顯示;
  • Overflow.visible 當(dāng)子控件超出Stack的顯示范圍時(shí)也顯示超出范圍的部分;

fit:子控件適應(yīng)Stack控件尺寸的方式,這個(gè)屬性對(duì)于非Positioned控件內(nèi)的子控件起作用。

  • StackFit.loose:使用此屬性時(shí),對(duì)于非Positioned控件內(nèi)的子控件,它的尺寸會(huì)小于Stack控件的尺寸,比如Stack的尺寸是300x600,那么子控件的尺寸寬度允許在0到300之間,高度允許在0到600之間;
  • StackFit.expand:使用此屬性時(shí),對(duì)于非Positioned控件內(nèi)的子控件,它的尺寸會(huì)撐滿Stack的尺寸。比如Stack的尺寸是300x600,那么子控件的尺寸寬度會(huì)是300,高度會(huì)是600;
  • StackFit.passthrough:對(duì)子控件的約束條件直接由Stack的父控件傳遞給Stack的子控件;
對(duì)應(yīng)Android中的match_parent和wrap_content

在Android中我們知道,每一個(gè)控件都可以直接設(shè)置寬高屬性為match_parent和wrap_content,選擇尺寸為充滿父布局還是包裹子控件內(nèi)容,使用非常方便。但是Flutter中沒有這樣的屬性可以直接使用,其實(shí)梳理完上面幾個(gè)常用容器控件的屬性之后,大致可以組合出與match_parent和wrap_content相同的效果,這樣,習(xí)慣了Android布局思維的同學(xué)轉(zhuǎn)過來寫Flutter控件也會(huì)順手和舒心很多,具體實(shí)現(xiàn)方式其實(shí)不止一種,以下是在stackoverflow上面找的一個(gè)答案,實(shí)測(cè)有效。

Wrap_content ,Wrap_content :
 //use this as child
 Wrap(
  children: <Widget>[*your_child*])
Match_parent,Match_parent:
 //use this as child
Container(
    height: double.infinity,
    width: double.infinity,child:*your_child*)
Match_parent,Wrap_content :
 //use this as child
Row(
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[*your_child*],
);
Wrap_content ,Match_parent:
 //use this as child
Column(
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[your_child],
);

尾聲

最后再貼一遍筆記對(duì)應(yīng)的Demo項(xiàng)目GitHub地址,點(diǎn)這里。
如果發(fā)現(xiàn)問題,歡迎斧正!
以上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 本文的目的是為了讓讀者掌握不同布局類Widget的布局特點(diǎn),分享一些在實(shí)際使用過程遇到的一些問題,在《Flu...
    xqqlv閱讀 5,415評(píng)論 0 18
  • Widget 分類 widget 其實(shí)是Element 的配置文件,而Element是右RenderObject ...
    Ray_lawq閱讀 793評(píng)論 0 1
  • 翻譯自“Auto Layout Guide”。 1 入門 1.1 理解自動(dòng)布局 自動(dòng)布局根據(jù)視圖層級(jí)結(jié)構(gòu)中視圖上的...
    lakerszhy閱讀 3,964評(píng)論 3 26
  • 轉(zhuǎn)自 Q吹個(gè)大氣球Q 本文主要介紹Flutter布局中的Flow、Table、Wrap控件,詳細(xì)介紹了其布局行為以...
    chilim閱讀 531評(píng)論 0 0
  • 箏&年 || 夢(mèng)回那一場(chǎng)屬于古箏的春晚 詩朗誦《為你讀箏》王昌元:有一種聲音,從祖屋的窗口飄出,帶有濕潤的江南味,...
    素琴齋書童閱讀 284評(píng)論 0 1

友情鏈接更多精彩內(nèi)容