前面課時只介紹了組件設(shè)計橄碾,并沒有過多涉及布局的講解卵沉,可能你了解一些布局組件,比如 Container法牲、Row史汗、Column、Padding拒垃、Center 等停撞,但是對于如何從 UI 稿到組件再到布局,卻沒有非常清晰的思路悼瓮。本課時就從我的角度來分析戈毒,如何進行組件的布局。
常見布局組件
在 Flutter 中可以分為 Single-child layout widgets 和 Multi-child layout widgets 横堡,使用中文來解釋就是單個子元素的布局組件和多個子元素的布局組件埋市。
Single-child
常見單個子組件的有 Align、Padding翅萤、 Expanded 和 Container 恐疲。
Align 比較好理解,Align 組件的位置左套么、右培己、上、下胚泌、左上省咨、右下、左下玷室、右上零蓉,這兩者一般配合 Container 來使用。
Padding 是一個可以設(shè)置上下和左右填充的組件穷缤,在布局設(shè)計中也非常常見敌蜂。
Expanded 是一個可伸縮的容器,可以根據(jù)子組件的大小進行動態(tài)伸縮津肛,這個需要配合 Row 組件的 flex 布局使用章喉,其次也可以作為動態(tài)列表的父組件,避免列表超出界面,引起布局問題秸脱。
Container 是比較常用的落包,類似一個容器,可以設(shè)置容器的大小摊唇,然后將子元素包裹在容器中咐蝇,該組件在超出容器后,會容易引起布局問題巷查。
Multi-child
常見的多個子組件有 Row有序、Column 和 Stack。
Row 是橫排展示子組件吮便。
Column 是豎排展示子組件笔呀。
Stack 是層疊展示子組件。
以上具體每個組件的參數(shù)配置髓需,大家可以在官網(wǎng)查到许师,官網(wǎng)還有一些不常用的,但也比較實用的布局組件僚匆,這里就不詳細列出了微渠。
布局思想
將布局的思想總結(jié)為八個字:豎、橫咧擂、高逞盆、寬、上松申、下云芦、左、右贸桶。 也就是一個頁面出來以后舅逸,按照這八個字的先后去分析頁面的布局。那么我們具體來看下皇筛,八個字中會涉及哪些布局組件的應(yīng)用琉历。
豎和橫
根據(jù)設(shè)計好的組件樹,從上往下分析水醋,遇到塊狀不同內(nèi)容組旗笔,則設(shè)計為一個 Column 的子元素。例如圖 2 的一個界面拄踪,從上往下分析蝇恶,我們可以得到 6 個 Column 布局組件的子組件(這里為了演示效果,我們把組件也設(shè)計為 6 個部分)惶桐。
圖 1 帖子詳情頁
分析完成以后艘包,我們再來看下每一行組件中所涉及的子組件的猛。行子組件一般也是基于:Container、Row想虎、Center 等布局組件來實現(xiàn)的,根據(jù)圖 1 的效果叛拷,我們來分析:
第一部分是居中的文章標題舌厨,可以使用 Center 組件;
第二部分是一條橫線忿薇,可以使用 Divider 來繪制一條分割直線裙椭;
第三部分是用戶信息,因為橫著是有兩個組件署浩,所以使用 Row揉燃;
第四部分是文章內(nèi)容,這里使用 Container 包裹一個 Text 組件筋栋;
第五部分是文章圖片炊汤,這里也使用 Container 包裹一個 Image 組件;
第六部分是一個組件弊攘,這個組件內(nèi)部豎看也是兩個組件抢腐,因此需要使用 Column 組件。
根據(jù)以上規(guī)則我們就可以設(shè)計出一個 pages 的頁面了襟交,代碼如下:
復(fù)制代碼
return Column(
? children: <Widget>[
? ? ArticleDetailTitle(title: contentDetail.title),
? ? Divider(),
? ? ArticleDetailUserInfoBar(userInfo: contentDetail.userInfo),
? ? ArticleDetailContent(content: contentDetail.detailInfo),
? ? ArticleDetailImg(articleImage: contentDetail.articleImage),
? ? ArticleDetailLike(articleId: id, likeNum: contentDetail.likeNum)
? ],
);
高和寬
接下來我們分析好每個組件所占用的高和寬迈倍,這部分可以在組件的 Container 屬性中設(shè)置,有些組件也自帶高和寬屬性捣域。例如上面的 Divider 組件我們就需要設(shè)置高和寬啼染,代碼如下:
復(fù)制代碼
return Column(
? children: <Widget>[
? ? ArticleDetailTitle(title: contentDetail.title),
? ? Divider(
? ? ? ? height: 1,
? ? ? ? color: Colors.lightBlueAccent,
? ? ? ? indent: 75,
? ? ? ? endIndent: 75
? ? ),
? ? ArticleDetailUserInfoBar(userInfo: contentDetail.userInfo),
? ? ArticleDetailContent(content: contentDetail.detailInfo),
? ? ArticleDetailImg(articleImage: contentDetail.articleImage),
? ? ArticleDetailLike(articleId: id, likeNum: contentDetail.likeNum),
? ? ArticleDetailComments(commentList: [])
? ],
);
上面代碼的第 5 行就是設(shè)置高,第 7 和第 8 行就是設(shè)置其寬度焕梅。
上和下
設(shè)置完每個組件的高和寬后迹鹅,我們再從上往下看。根據(jù)組件樹丘侠,這里主要看 Column 組件下的所有子組件之間是否需要設(shè)置上下徒欣,如果需要則應(yīng)用 Padding 來實現(xiàn)。為了效果蜗字,我們在 ArticleDetailContent 和 ArticleDetailUserInfoBar 之間增加一個 Padding 效果打肝,代碼如下:
復(fù)制代碼
return Column(
? children: <Widget>[
? ? ArticleDetailTitle(title: contentDetail.title),
? ? Divider(
? ? ? ? height: 1,
? ? ? ? color: Colors.lightBlueAccent,
? ? ? ? indent: 75,
? ? ? ? endIndent: 75
? ? ),
? ? ArticleDetailUserInfoBar(userInfo: contentDetail.userInfo),
? ? Padding(padding: EdgeInsets.only(top: 2)),
? ? ArticleDetailContent(content: contentDetail.detailInfo),
? ? ArticleDetailImg(articleImage: contentDetail.articleImage),
? ? ArticleDetailLike(articleId: id, likeNum: contentDetail.likeNum),
? ? ArticleDetailComments(commentList: [])
? ],
);
左和右
整體設(shè)置完成后,我們再來看下組件左右的間隔設(shè)置挪捕。這里主要看 Row 組件下的所有子組件粗梭,檢查是否需要 Padding 屬性。其次判斷 Row 子組件是否需要設(shè)置左右占比级零,如果需要則使用到 flex 布局中的 Expanded 組件断医。比如上面組件中的 ArticleDetailUserInfoBar 需要左右布局設(shè)計滞乙,因此根據(jù)規(guī)則我們看下 ArticleDetailUserInfoBar 的代碼邏輯。具體代碼如下:
復(fù)制代碼
@override
Widget build(BuildContext context) {
? return Container(
? ? color: Colors.white,
? ? padding: EdgeInsets.all(8),
? ? child: Row(
? ? ? mainAxisAlignment: MainAxisAlignment.spaceBetween,
? ? ? children: <Widget>[
? ? ? ? Expanded(
? ? ? ? ? flex: 4,
? ? ? ? ? child: Row(),
? ? ? ? Expanded(
? ? ? ? ? flex: 1,
? ? ? ? ? child: Row(),
? ? ? ],
? ? ),
? );
}
上面的代碼中可以看到該組件使用 Container 包裹鉴嗤,其次使用了 Row 組件斩启,假設(shè)我們 UI 稿中的圖 3 部分是左右 4 : 1 布局,因此在代碼中第 10 行設(shè)置前面組件為 4 醉锅,第 13 行設(shè)置后面組件為 1兔簇。
這樣就完成了外部組件的設(shè)計,以上 6 個組件就可以寫一部分偽代碼去實現(xiàn)了硬耍。外部組件設(shè)計完成后垄琐,我們開始通過 8 個過程來進行子組件布局設(shè)計,對于其中的 8 個過程经柴,并不是每個組件都需要狸窘,因此越到根節(jié)點布局設(shè)計過程會越少。
根據(jù)以上設(shè)計原則坯认,我們就實現(xiàn)了帖子詳情部分的布局設(shè)計翻擒。具體代碼實現(xiàn)在 github 源碼中的 pages/article_detail/index.dart 中。接下來我將用上面的原則來設(shè)計我們 Two You Friend App 的“客人態(tài)主頁”頁面鹃操。
實踐應(yīng)用
我們先來看下我們需要實現(xiàn)的效果韭寸,如圖 2 所示。
圖 2 客人態(tài)頁面
根據(jù)圖 2 的界面我們還是先繪制一個組件樹荆隘,如圖 3 所示恩伺。
圖 3 客人態(tài)組件樹設(shè)計
接下來,我們在圖 3 的基礎(chǔ)上椰拒,應(yīng)用布局設(shè)計的 8 個過程晶渠,一步步來優(yōu)化這個組件樹。
豎和橫
豎著來看四個組件分別為 guest 的 Column 子組件燃观,因此需要標記為 Column褒脯。然后再橫著看每個子組件:
guest_header,包含兩部分左邊為 user_info 組件(其中又包含 Image 和 Text)缆毁,右邊為 Icon 組件番川;
Divider,是一條分割線脊框;
guest_bar颁督,包含了三個并列的組件,分別是 Icon浇雹、Icon 和 Text沉御;
content_list,這個應(yīng)用 article_card 子組件即可昭灵,該組件已經(jīng)在前面介紹過具體設(shè)計吠裆。
分析完后伐谈,我們將會得到圖 4 組件樹。
圖 4 組件樹+布局設(shè)計
從圖 4 我們可以看到试疙,在組件與組件之間增加了布局組件的應(yīng)用 Column 诵棵、Row 和 Expanded。
高和寬
上面組件中效斑,有兩個組件是需要設(shè)置的非春,一個是 Divider ,一個是 content_list 缓屠。后者需要設(shè)置的目的是,因為列表組件超出會引起布局異常护侮。因此 content_list 是需要使用 Expanded 來包裹敌完,這部分可以不體現(xiàn)在界面中。
上和下
由于圖 2 這里就沒有需要設(shè)置上下的間隔羊初,因此組件圖也不需要修改滨溉。這里主要看每個 Column 組件下的子節(jié)點。
左和右
根據(jù)這個規(guī)則长赞,我們看下每個 Row 組件下的子節(jié)點之間是否需要設(shè)置 Padding 晦攒。根據(jù) UI 稿分析,我們可以了解到 user_info 和 guest_bar 組件的子組件都需要設(shè)置左右填充得哆,因此在圖 2 基礎(chǔ)上脯颜,我們增加 Padding 布局設(shè)計,并重新繪制組件圖贩据,可以最終得到圖 5 的一個組件+布局的設(shè)計結(jié)果栋操。
圖 5 組件樹+布局設(shè)計結(jié)果
在將組件樹和布局設(shè)計完成后,我們再去進行組件的代碼編寫饱亮,這部分代碼大家可以前往 github 的源碼的 pages/user_page/guest.dart 文件中查看矾芙,具體的代碼比較相似,這里就不過多介紹了近上。
總結(jié)
本課時介紹了幾個常用的布局組件和布局設(shè)計的思想(8 個過程)剔宪,最后通過實現(xiàn)“客人態(tài)主頁“來實踐組件樹+布局的設(shè)計思想。相關(guān)頁面的知識點就介紹完了壹无,接下來我會在源碼中更新其他界面內(nèi)容葱绒,對于比較核心的一些知識點我們還會在 18 課時中介紹,其他重復(fù)知識點格遭,就不再介紹了哈街。
下一課時我們將帶著現(xiàn)有的 Two You Friend App 代碼,教大家如何打包 Android 和 iOS 發(fā)布包拒迅。
轉(zhuǎn)自:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=251#/detail/pc?id=3533