iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 8
0
Mobile Development

30天手滑用Google Flutter解鎖Hybrid App成就系列 第 8

30天Flutter手滑系列 - 布局組件(Layout Widgets)(下)

好的Layout讓你的UI畫面看起來很有那麼一回事,後端code再爛都沒關係,接續上一篇30天Flutter手滑系列 - 布局組件(Layout Widgets)(上),接下來要介紹如何安撫多個children乖乖排列的故事。

布局組件(Layout widgets)

- 多組件布局(Multi-child layout widgets)

1. Row

https://ithelp.ithome.com.tw/upload/images/20190915/20120028AtHAz1hhi8.png

很直觀的把children排列成一列,但其本身是不能夠被捲動的,而且超過Row能容納的範圍會產生錯誤。
另外如果有WEB flexbox的基礎,排列children的相對概念是滿接近的。

在Row,有幾個重要的屬性:

  • mainAxisAlignment:表示children在X上對齊的位置。
    • center:將children放置在軸心。
    • start:將children放置在起點,也是預設值。
    • spaceAround:將children之間的空白相等,但頭尾child距離會是1/2。
    • spaceBetween:將children之間的空白相等,但頭尾child距離頭尾距離為0。
    • spaceEvenly:將所有children之間的空白距離相等。
    • end:將children靠終點排列。
  • mainAxisSize:在X上佔的位置,預設為max,表示盡可能占用所有空間。
  • crossAxisAlignment:表示children在Y軸上對齊的位置。
    • baseline:將children對齊本身的baseline。
    • start:將children對齊Y軸的起點。
    • center:將children對齊Y軸的中心。
    • end:將children對齊Y軸的最末點。
    • stretch:使children填滿整個Y軸。
  • textDirection:設定children排列的順序是由左到右還是由右到左。
  • verticalDirection:設定children的排列順序,預設是由上到下。

https://ithelp.ithome.com.tw/upload/images/20190915/20120028sLfGszoa6f.png

下面範例示範一個簡單的Row布局:
https://ithelp.ithome.com.tw/upload/images/20190915/20120028WvhtxSAlwk.png

Row(
  children: <Widget>[
    Expanded(
      child: Text('Deliver features faster', textAlign: TextAlign.center),
    ),
    Expanded(
      child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
    ),
    Expanded(
      child: FittedBox(
        fit: BoxFit.contain, // otherwise the logo will be tiny
        child: const FlutterLogo(),
      ),
    ),
  ],
)

2. Column

https://ithelp.ithome.com.tw/upload/images/20190915/20120028J6rsr7n3Ca.png

Column跟Row基本上差不多的,一個垂直,一個水平排列。
一樣有超過column大小會產生錯誤,以及不能夠捲動的特性。
屬性設定的概念剛好跟Row是相反。

來看個簡單的範例:
https://ithelp.ithome.com.tw/upload/images/20190915/20120028TO48hfMidU.png

Column(
  children: <Widget>[
    Text('Deliver features faster'),
    Text('Craft beautiful UIs'),
    Expanded(
      child: FittedBox(
        fit: BoxFit.contain, // otherwise the logo will be tiny
        child: const FlutterLogo(),
      ),
    ),
  ],
)

3. ListView

https://ithelp.ithome.com.tw/upload/images/20190915/20120028uio3il6Kmp.png

ListView是最常被使用的滾動組件,可以沿著一個方向排列所有children。

在ListView比較重要的屬性如下:

  • itemExtent:如果捲動方向為垂直,則預設指定child的高度作為捲動的高度。如果捲動方向是水平,則預設指定child的寬度作為捲動寬度。
  • shrinkWrap:捲動的高度是否由內容高度決定,false情況下會佔用最大允許高度。如果在無邊界的容器中捲動,需要設為true,否則會有錯誤。預設值為false。
  • addAutomaticKeepAlives:是否將children包裹在AutomaticKeepAlive這個組件中。例如當內容滑出可視範圍時,並不會被回收(Garbage Collection),會被KeepAliveNotification保存。
  • addRepaintBoundaries:是否將children包裹在RepaintBoundary這個組件中,避免捲動時重繪。如果重繪的成本較小,應設為false,效能會比較好。

下面範例是一個簡單的ListView:
https://ithelp.ithome.com.tw/upload/images/20190915/20120028CfFrazWQfj.png

ListView(
  padding: const EdgeInsets.all(8),
  children: <Widget>[
    Container(
      height: 50,
      color: Colors.amber[600],
      child: const Center(child: Text('Entry A')),
    ),
    Container(
      height: 50,
      color: Colors.amber[500],
      child: const Center(child: Text('Entry B')),
    ),
    Container(
      height: 50,
      color: Colors.amber[100],
      child: const Center(child: Text('Entry C')),
    ),
  ],
)

4. GridView

https://ithelp.ithome.com.tw/upload/images/20190915/20120028U740EnfbA8.png

繪製一個可捲動的二維列表。大致用法跟ListView差不多。

比較特別的有以下屬性:

  • gridDelegate:用來控制children如何進行布局。

以下範例是基本的GridView,額外設置了crossAxisSpacing(主軸方向間距)和mainAxisSpacing(橫軸方向間距)兩個屬性。
https://ithelp.ithome.com.tw/upload/images/20190915/20120028gpRqeOzzuY.png

GridView.count(
  primary: false,
  padding: const EdgeInsets.all(20),
  crossAxisSpacing: 10,
  mainAxisSpacing: 10,
  crossAxisCount: 2,
  children: <Widget>[
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('He\'d have you all unravel at the'),
      color: Colors.teal[100],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Heed not the rabble'),
      color: Colors.teal[200],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Sound of screams but the'),
      color: Colors.teal[300],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Who scream'),
      color: Colors.teal[400],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Revolution is coming...'),
      color: Colors.teal[500],
    ),
    Container(
      padding: const EdgeInsets.all(8),
      child: const Text('Revolution, they...'),
      color: Colors.teal[600],
    ),
  ],
)

5. Stack

https://ithelp.ithome.com.tw/upload/images/20190915/20120028JNmKAYM4pr.png

Stack可以想像成Web中的absolute或是Android的Frame。
其定位方式根據top、bottom、left和right來完成。

有以下重要屬性:

  • alignment: 決定定位方式,預設是左上。
  • fit: 定義没有定位(non-positioned)的children如何去適應stack大小。
    • loose: 以children的大小去適應整個stack
    • expand: children會以stack的大小去擴展。
    • passthrough: 不改變child的約束限制。
  • textDirection: 用於決定alignment對齊的位置。
  • overflow: 決定超過範圍的部分是否會被切掉(clipped)。

以下是利用Stack排列的範例:
https://ithelp.ithome.com.tw/upload/images/20190915/20120028xbMUyCLXpp.png

Stack(
  children: <Widget>[
    Container(
      width: 100,
      height: 100,
      color: Colors.red,
    ),
    Container(
      width: 90,
      height: 90,
      color: Colors.green,
    ),
    Container(
      width: 80,
      height: 80,
      color: Colors.blue,
    ),
  ],
)

總結

布局就先介紹到這了,其實不止這些,不過常用跟重要的都已經列出。
每天都覺得時間不夠,先這樣了,有空再來慢慢補充。


參考資料

https://flutter.dev/docs/development/ui/widgets/layout
https://juejin.im/post/5b623d8c5188257f0b583c77


上一篇
30天Flutter手滑系列 - 布局組件(Layout Widgets)(上)
下一篇
30天Flutter手滑系列 - 導航與路由(Navigation & Routing)
系列文
30天手滑用Google Flutter解鎖Hybrid App成就30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言