不知不覺(jué)已經(jīng)到了第7篇罐栈,然而很多萌新玩家可能還是不知道如何堆砌控件黍衙,像用CSS一樣搭出漂亮的APP界面,我也一樣荠诬,紅紅火火恍恍惚惚琅翻,直到今天含淚讀完Flutter布局基礎(chǔ),仿佛打開(kāi)了一個(gè)全新的世界柑贞。
基本概念
在flutter中方椎,一切皆控件!一切皆控件钧嘶!一切皆控件棠众!牢牢記住這個(gè)概念。Text是控件有决,Image是控件闸拿,Icon是控件,布局腳手架也Scaffold也是控件书幕,甚至整個(gè)APP也是控件胸墙。
用戶自定義控件分為有狀態(tài)控件和無(wú)狀態(tài)控件兩種類型,其特性在前面的筆記4中可以感受感受按咒。
flutter的內(nèi)置控件分為兩種:
- 可視控件(visible widget)。即我們直接看到的控件但骨,如text励七、Icon、Button奔缠,名稱理解和html標(biāo)簽相同掠抬。
- 布局控件(layout widget)⌒0ィ可以理解為架子两波,如Row瞳步、Column、Container腰奋。布局控件不會(huì)直接呈現(xiàn)內(nèi)容单起,可看作承載可視控件的容器。所有的布局控件都有承載子控件的屬性:
child
或children
劣坊。child
可承載單個(gè)子控件嘀倒,children
可承載多個(gè)子控件。每個(gè)布局控件有默認(rèn)的布局方式局冰,使其子控件按照自己的樣式安放到位子上测蘑。布局控件提供了各種樣式的參數(shù),可實(shí)現(xiàn)子控件的對(duì)齊(align)康二、縮放(size)碳胳、包裝(pack)和嵌套(Nest)。簡(jiǎn)單總結(jié)為:布局控件是為了實(shí)現(xiàn)可視控件的各種視覺(jué)效果而做的包裝沫勿,比如前端的html為了實(shí)現(xiàn)sticky挨约、雙飛翼、圣杯等布局常常內(nèi)容區(qū)外層添加div包裹層藕帜。
布局控件也是可以模擬顯示的烫罩,通常用于調(diào)試布局樣式時(shí)用到的網(wǎng)格線、標(biāo)尺洽故、動(dòng)畫(huà)幀等贝攒。啟用方式:
1.在main.dart中,引入包:
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
2.在main
函數(shù)中打開(kāi)開(kāi)關(guān):
void main() {
debugPaintSizeEnabled = true; //打開(kāi)視覺(jué)調(diào)試開(kāi)關(guān)
runApp(new MyApp());
}
運(yùn)行代碼后APP效果如下:
flutter的內(nèi)置控件已經(jīng)定義了很多屬性时甚,玩家可以參考Widgets Catalog了解每種控件的詳細(xì)屬性和用法隘弊。本篇通過(guò)幾個(gè)例子,介紹頁(yè)面上的控件如何堆砌和布局荒适。
別著急梨熙,由于下面的案例中,可能用到圖片刀诬,先交待一下加載圖片的基本配置方法:
- 到項(xiàng)目根目錄下創(chuàng)建一個(gè)文件夾咽扇,命名:images,將圖片放置到該文件夾中陕壹。
- 打開(kāi)根目錄下的pubspec.yaml文件质欲,在其下添加注釋中的屬性:
flutter:
uses-material-design: true
assets: //如果沒(méi)有這個(gè)屬性則添加到flutter標(biāo)簽下
- images/lake.jpg //聲明圖片的路徑
- 到代碼中,以image控件的方式引用圖片:
new Image.asset(
'images/lake.jpg', //圖片的路徑
width: 600.0, //圖片控件的寬度
height: 240.0, //圖片控件的高度
fit: BoxFit.cover, //告訴引用圖片的控件糠馆,圖像應(yīng)盡可能小嘶伟,但覆蓋整個(gè)控件。
),
案例
控件的排列
行(Row)和列(Column)又碌,是flutter中最常用的兩個(gè)布局控件九昧,他們只能容納當(dāng)前屏幕尺寸大小的內(nèi)容绊袋,如果其內(nèi)部的子控件超出屏幕尺寸,不但不會(huì)自動(dòng)生成滾動(dòng)條铸鹰,還會(huì)報(bào)錯(cuò)癌别。
案例1-行排列
如圖上圖所示,圖中有3個(gè)100px寬的圖片掉奄,通過(guò)水平平均間隔的方式居中橫向排列顯示到一行中规个,代碼示例:
new Center( //居中控件
child: new Row( //行控件
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //對(duì)齊方式:平均間隔
children: [
new Image.asset('images/pic1.jpg'), //引入三張圖片
new Image.asset('images/pic2.jpg'),
new Image.asset('images/pic3.jpg'),
]
)
)
可以看到上圖用到了2個(gè)布局控件Center和Row,通過(guò)Center包裹Row姓建,使行控件保持居中诞仓,而ROW控件包裹了3個(gè)圖片控件Image,通過(guò)配置Row的mainAxisAlignment對(duì)齊屬性速兔,使三個(gè)圖片空間通過(guò)平均間隔的方式進(jìn)行橫向排列墅拭。
完整代碼:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
案例2-列排列
如上圖所示,還是那3張圖涣狗,通過(guò)縱向平均間隔的方式顯示到一列中谍婉,代碼如下:
new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //對(duì)齊方式:平均間隔
children: [
new Image.asset('images/pic1.jpg'),
new Image.asset('images/pic2.jpg'),
new Image.asset('images/pic3.jpg'),
]
)
)
完整代碼:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
對(duì)比案例1和2可以看到,代碼結(jié)構(gòu)相同镀钓,Row和Column中都用到了mainAxisAlignment屬性穗熬,除此以外還有crossAxisAlignment屬性。值得注意的是丁溅,在Row中mainAxisAlignment控制水平方向?qū)R唤蔗,crossAxisAlignment控制垂直方向?qū)R,而在Column中則正好相反窟赏。相關(guān)參數(shù)值請(qǐng)參考MainAxisAlignment和CrossAxisAlignment
布局控件的嵌套
案例3-行列嵌套
如上圖妓柜,我們將圖中的元素按圖中的框線進(jìn)行分解:
1.最外層的使用Row控件包裹,使其內(nèi)部的兩個(gè)子控件:淺藍(lán)色框的菜品介紹和右邊的菜品大圖橫向排列涯穷,代碼如下:
new Scaffold( //腳手架控件
appBar: new AppBar( //工具欄控件
title: new Text(widget.title),
),
body: new Center(
child: new Container( //Container控件用于調(diào)整外邊距
margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),
height: 600.0,
child: new Card( //Card控件控制卡片的視覺(jué)效果
child: new Row( //Row控件使其子控件橫向排列
crossAxisAlignment: CrossAxisAlignment.start, //縱向?qū)R方式:起始邊對(duì)齊
children: [
new Container( //Container控件用于調(diào)整寬度
width: 440.0,
child: leftColumn, //左邊的菜品介紹控件
),
mainImage, //右邊的大圖控件
],
),
),
),
)
)
2.把淺藍(lán)色框內(nèi)的信息棍掐,用Column包裹,使其內(nèi)容垂直排列:
new Container(
padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0),
child: new Column( //Column控件拷况,使其子控件垂直排列
children: [
titleText, //標(biāo)題行作煌,包含了可視Text控件
subTitle, //副標(biāo)題行,包含了可視Text控件
ratings, //投票信息行
iconList, //小圖標(biāo)行
],
),
);
3.由于titleText和subTitle都是簡(jiǎn)單的包裝了Text控件赚瘦,不再貼代碼和注釋最疆,重點(diǎn)講下ratings和iconList:
ratings和iconList控件是垂直排列的兩行,而各自內(nèi)部有自己的布局信息蚤告,因此將這兩行分別拆解為:
ratings下包含了兩個(gè)水平排列:Row控件用于顯示星級(jí),Text控件用于顯示用戶瀏覽數(shù)服爷。而評(píng)分星級(jí)控件ROW又分解為5個(gè)水平排列的Icon控件杜恰。
iconList橫向排列了3個(gè)縱向顯示的控件获诈,層次一目了然。
對(duì)照代碼結(jié)構(gòu):
//ratings控件
new Container(
padding: new EdgeInsets.all(20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Row(
mainAxisSize: MainAxisSize.min, //mainAxisSize心褐,可壓縮或伸長(zhǎng)行內(nèi)控件的間距
children: [
new Icon(Icons.star, color: Colors.black),
new Icon(Icons.star, color: Colors.black),
new Icon(Icons.star, color: Colors.black),
new Icon(Icons.star, color: Colors.black),
new Icon(Icons.star, color: Colors.black),
],
),
new Text(
'170 Reviews',
style: new TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20.0,
),
),
],
),
)
//iconList控件
new Container(
padding: new EdgeInsets.all(20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Column(
children: [
new Icon(Icons.kitchen, color: Colors.green[500]),
new Text('PREP:'),
new Text('25 min'),
],
),
new Column(
children: [
new Icon(Icons.timer, color: Colors.green[500]),
new Text('COOK:'),
new Text('1 hr'),
],
),
new Column(
children: [
new Icon(Icons.restaurant, color: Colors.green[500]),
new Text('FEEDS:'),
new Text('4-6'),
],
),
],
),
)
Row和Column可以相互包裹舔涎,使頁(yè)面能夠?qū)崿F(xiàn)整齊的布局,只因其特性總是橫向或縱向充滿父控件逗爹,比如最外層使用時(shí)亡嫌,會(huì)自動(dòng)充滿全屏幕。但是當(dāng)頁(yè)面內(nèi)容需要超出屏幕尺寸時(shí)掘而,就用ListTile和ListView代替挟冠。
完整代碼(由于手機(jī)屏幕尺寸無(wú)法適應(yīng)此案例,運(yùn)行后長(zhǎng)和寬都會(huì)報(bào)溢出錯(cuò)誤袍睡,大家最好使用平板虛擬機(jī)測(cè)試此案例知染,或者調(diào)整代碼中的字體大小和控件尺寸,以滿足顯示要求):
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
控件的縮放
案例4-縮放
上圖中斑胜,三個(gè)橫向排列的圖片控件控淡,中間控件的尺寸比兩邊的大一倍,代碼如下:
new Center(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new Expanded(
child: new Image.asset('images/pic1.jpg'),
),
new Expanded( //使用Expanded控件對(duì)Image控件進(jìn)行包裹
flex: 2, //flex值默認(rèn)為1止潘,這里改成2之后掺炭,其子控件2倍放大
child: new Image.asset('images/pic2.jpg'),
),
new Expanded(
child: new Image.asset('images/pic3.jpg'),
),
))
完整代碼:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
由于處理邏輯和布局樣式都一起書(shū)寫(xiě)到代碼中,加上控件的嵌套凭戴,flutter的代碼會(huì)如同html的標(biāo)簽一樣嵌套很多層涧狮,對(duì)前端開(kāi)發(fā)者可能需要時(shí)間適應(yīng),但對(duì)我這種新萌來(lái)說(shuō)降低了從CSS和處理代碼之間來(lái)回對(duì)照的麻煩簇宽,并且flutter的內(nèi)置控件默認(rèn)的樣式已經(jīng)十分整潔勋篓,無(wú)需單獨(dú)再學(xué)習(xí)類似前端CSS處理頁(yè)面布局的語(yǔ)法和結(jié)構(gòu),總體來(lái)說(shuō)降低了不少學(xué)習(xí)成本魏割,上手更快更簡(jiǎn)單譬嚣。能在短時(shí)間內(nèi)掌握生產(chǎn)技能,成就感油然而生钞它,自然有繼續(xù)學(xué)下去的動(dòng)力拜银。
以上便是最基礎(chǔ)的排列布局介紹,相信看到這里的小伙伴已經(jīng)明白怎么寫(xiě)APP了遭垛,今天就到這里~感謝大家支持尼桶!
flutter 中文社區(qū)(官方QQ群:338252156)