iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

Flutter web 的奇妙冒險系列 第 17

Day 17 | Flutter的常用 widgets - Container、Row、Column

  • 分享至 

  • xImage
  •  

StatefulWidget 的build

回到昨天 StatefulWidget 的 build

https://ithelp.ithome.com.tw/upload/images/20210930/20112906GVWMdP32Cx.png

會先看到 Scaffold 這個 widget ,這是一個Material 所提供的一個基本的排版widget,通常都會當作一個頁面的開始,這裡有用上三個參數 appBarbodyfloatingActionButton

appBar 就是app最上方的工具列, 這裡是用 AppBar 這個widget ,主要就是一些頁面標題或者操作選單或回到上一頁按鈕會出現在這裡,appBar的型別是 PreferredSizeWidget ,所以其實只要是PreferredSizeWidget 都可以傳進 appBar 也不一定要用AppBar 就是了。

然後是body 就是主要的顯示區塊,通常都會放置我們主要要操作及顯示的Widgets。

floatingActionButton 則是那顆懸浮按鈕通常會是那頁最主要的操作,像是google導航的導航按鈕就是做在這顆按鈕。而他的位置預設會是右下角也可以使用其他參數來控制他的位置。

body 裡的 widget其實我們光是看命名也很好猜出他們的功能是什麼, Center 就是置中用、 Column 就是一個直行的容器, Text 就是放文字的。這裡就能體會到 aggressive composability 的好處就是當每個功能/排版/容器都是一個widget時我們可以從命名就能知道他的作用是什麼,而缺點是等你開始組成一個複雜的layout你會發現這個深度會令人無法直視。

常用widget

就 flutter 官方上的 widget 列表的數量來說一個一個介紹顯然不切實際,所以大概就只會簡介一下常用的widget。

通常我在找我想用的widget時如果是沒有比較複雜互動的widget的話,我傾向先去我 catalog 來查找,當然如果真的很複雜的功能就會去找第三方套件之類的。

所以我們來看一下這個 catalog 有哪些常用的widget。

基本上最最最常用的還是 Layout 這個分類的widget,在這個分類下有分成這三種widget。

Single-child layout widgets

接受widget的參數是 child 也就是只能傳入單一個 widget 的 widget,像是 ContainerSizedBoxExpandedPadding 等等。

Multi-child layout widgets

接受widget的參數是 children 所以就是能傳入 List<Widget> ,這類的有 RowColumnStackListViewGirdView 等等。

Sliver widgets

可以自定義滾動效果的widget,但這部分我就沒有實作就不額外說明了。

Container

而另外一個最常用的就是 Container ,基本上是可以想像成沒有很自由的 div 在使用,大部分是拿來當作一個元件的基底widget,可以設定固定寬高及padding,可以使用 decoration 做額外的樣式等等設定。

Container(
	width: 300,
  height: 300,
  child: Text('這是一個高寬都是300px的Container'),
  decoration: BoxDecoration(color: Colors.black26),
),

https://ithelp.ithome.com.tw/upload/images/20210930/20112906vubUXjiz1F.png

Row Column

在Flutter中的RowColumn 都是flex的所以如果有寫過網頁前端的讀者應該能蠻容易理解Row、Column的排版邏輯。

基本上跟css中的flexBox的概念一樣,會有兩條軸與主軸方向平行一致就是Main Axis與之垂直就是Cross Axis。

https://ithelp.ithome.com.tw/upload/images/20210930/201129068DZrat0xwX.png
https://ithelp.ithome.com.tw/upload/images/20210930/20112906BSoPWAN9gL.png

所以在預設專案的這段中

 Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text(
          'You have pushed the button this many times:',
        ),
        Text(
        '$_counter',
        style: Theme.of(context).textTheme.headline4,
        ),
      ],
    ),

ColumnmainAxisAlignment 的意思是指在主軸上的對齊模式,所以以上面例子來看就是:對在主軸方向置中,也就是從畫面上是垂直置中。

MainAxisAlignment 總共有幾個值

MainAxisAlignment.start: 盡可能將children向主軸起點放置

MainAxisAlignment.end: 盡可能將children向主軸終點放置

MainAxisAlignment.center: 盡可能將children向主軸中間放置

MainAxisAlignment.spaceBetween: 將剩餘間距分散在各元素之間但第一個元素的前面及最後一個沒有間距。

MainAxisAlignment.spaceAround: 將剩餘間距分散在各元素之間但第一個元素的前面及最後一個沒只有一半的間距。

MainAxisAlignment.spaceEvenly: 將間距平均分散在每個元素之間包含第一個元素的前面及最後一個元素後面

使用 Row 來排列的話,這三者的差異在畫面上的差異是這樣:

https://ithelp.ithome.com.tw/upload/images/20210930/20112906aM4Ba2PVKP.png

CrossAxisAlignment 則是垂直軸的排列方式:

CrossAxisAlignment.start:元素的開始位置是在垂直軸的起點

CrossAxisAlignment.end:元素的開始位置是在垂直軸的終點

CrossAxisAlignment.center:元素的開始位置是在垂直軸的中間

CrossAxisAlignment.stretch:將元素佔滿垂直軸

CrossAxisAlignment.baseline:將元素按照垂直軸的基準線排列(不常用)

Row 來說 CrossAxisAlignment.start 就是元素會貼著上面,CrossAxisAlignment.center就會是垂直置中。

Row及Column的要注意的一點是 「不能換行」 ,他們就是單純的一條線,如果超出外面容器的寬度就會直接跳出錯誤。

這邊是一個 Container 包著 Column 再包 Row

Container(
  width: 300,
  child: Column(
  children: [
	  Text('這是一個寬度300px的Container'),
		  Row(
			  children: [
		      ...List.generate(
		          5,
		          (_) => const Text('123456456'),
		          )
		        ],
		      )
		    ],
		  ),
	decoration: BoxDecoration(color: Colors.black26),
),
    

https://ithelp.ithome.com.tw/upload/images/20210930/201129066daptvvxb4.png

以這個例子來說通常是會將 Row 換成 Wrap 來達成換行的需求。

Container(
  width: 300,
  child: Column(
  children: [
	  Text('這是一個寬度300px的Container'),
		  Wrap(
			  children: [
		      ...List.generate(
		          5,
		          (_) => const Text('123456456'),
		          )
		        ],
		      )
		    ],
		  ),
	decoration: BoxDecoration(color: Colors.black26),
),
    

https://ithelp.ithome.com.tw/upload/images/20210930/20112906e5norVmztW.png


我個人是覺得會使用 ContainerRowColumn 就能完成一些很基礎的排版需求了,剩下的等實際開發時遇到再來說明。

明天就來做我們第一個小專案也順便開始真正的運用狀態管理。


上一篇
Day 16 | 第一個 Flutter 專案
下一篇
Day 18 | 萬年範例-TodoList
系列文
Flutter web 的奇妙冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言