前言
前面兩篇文章給大家介紹了Widget中對應原生開發中的一些常用基礎控制元件,Text、TextField、Button、Dialog、Picker等,本篇我們將和大家一起學習ListView、GridView等列表網格佈局控制元件和其他常用的用於佈局的Widget,如Container、Row、Column、Padding等等。
列表和網格檢視Widget
ListView
ListView通常有兩種用法:第一種實現類似於安卓中ScrollView和iOS中UIScrollView;第二種實現類似於安卓中的ListView和iOS中的UITableView。
通過ListView()建立
直接通過ListView()建立,主要屬性介紹如下:
-
scrollDirection
表示控制元件滾動的方向,主要有兩個值可設定。Axis.vertical表示垂直滾動檢視;Axis.horizontal表示水平滾動檢視。
-
reverse
表示讀取內容的方向是否顛倒,可設定值為true|false。false表示由左向右或由上向下讀取;true表示由右向左或由下向上讀取。
-
primary
可設定值為true|false。true時表示內容不足夠填充控制元件區間時也可以有滾動反饋;false表示只有內容超出控制元件大小時才可滾動。
-
physics
表示物理反饋,一般設定值為AlwaysScrollableScrollPhysics()|ScrollPhysics()。AlwaysScrollableScrollPhysics表示總是有滾動反饋,無論primary值為true or false;ScrollPhysics表示只有只有內容超出控制元件大小時才會有滾動反饋,無論primary值為true or false。
-
padding
表示控制元件的內邊距。
-
controller
表示用於控制檢視滾動位置的控制器物件,設定此屬性時primary屬性值必須為false,否則報錯,可通過scrollController.jumpTo(0.0)讓滾動檢視回到最頂端或最左位置。
-
itemExtent
表示單個條目的範圍,即指item的高度(scrollDirection為Axis.vertical時)或寬度(scrollDirection為Axis.horizontal時)。
-
children
表示列表包含的widget集合,整個滾動檢視中的內容設定。
var scrollController = ScrollController();
Widget getListView() {
return ListView(
scrollDirection: Axis.vertical,
reverse: false,
primary: false,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.all(25),
controller: scrollController,
itemExtent: 50,
children: <Widget>[
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('I\'m dedicating every day to you'),
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('I\'m dedicating every day to you'),
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('I\'m dedicating every day to you'),
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('And I thought I was so smart'),
const Text('I\'m dedicating every day to you'),
const Text('I\'m dedicating every day to you'),
const Text('Domestic life was never quite my style'),
const Text('When you smile, you knock me out, I fall apart'),
const Text('And I thought I was so smart'),
const Text('I\'m dedicating every day to you'),
MaterialButton(
color: Colors.blueAccent,
textColor: Colors.white,
child: Text('返回頂部'),
onPressed: () {
scrollController.jumpTo(0.0);
},
),
],
);
}
複製程式碼
具體效果如下:
通過ListView.builder()建立
當建立動態列表或包含大量資料的列表時,使用此方法建立,其會自動回收列表元素。相當於安卓中的可複用itemView的ListView或RecyclerView和iOS中可複用UITableCell的UITableView或可複用UICollectionViewCell的UICollectionView,主要的兩個屬性為:
-
itemCount
表示列表的條目總數量。
-
itemBuilder
一個建立item Widget的函式:Widget Function(BuildContext context, int index),通過實現改函式來建立item內容,index表示條目的位置索引。
Widget getListViewBuilder() {
return ListView.builder(
scrollDirection: Axis.vertical,
reverse: false,
itemExtent: 50,
itemCount: 30,
itemBuilder: (buildContext, index) {
return Text('This is num : $index', style: TextStyle(fontSize: 20, color: index % 2 == 0 ? Colors.blueAccent : Colors.redAccent),);
},
);
}
複製程式碼
具體效果如下:
GridView
網格檢視在UI介面開發時也是很常用的,比如相簿、視訊列表中經常會遇到,Flutter中通常使用GridView.count()和GridView.builder()方法來建立網格檢視。
通過GridView.count()建立
其主要的一些屬性有部分和ListView中屬性相同,不同的屬性如下:
-
crossAxisCount 表示垂直於主軸方向上的單元格Widget數量。如果scrollDirection為Axis.vertical,則表示水平單元格的數量;如果scrollDirection為Axis.horizontal,則表示垂直單元格的數量。
-
mainAxisSpacing
表示主軸方向單元格的間距。
-
crossAxisSpacing
表示垂直於主軸方向的單元格間距。
-
childAspectRatio
表示單元格的寬高比。
-
children
表示所有單元格中Widget的集合,GridView裡展示的內容。
Widget getGridView() {
return GridView.count(
scrollDirection: Axis.vertical,
reverse: false,
controller: scrollController,
primary: false,
physics: AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.all(15.0),
crossAxisCount: 2,
mainAxisSpacing: 30.0,
crossAxisSpacing: 15.0,
childAspectRatio: 1.5,
children: <Widget>[
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Banana'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Orange'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Tomato'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Banana'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Orange'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Tomato'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Banana'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Orange'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Tomato'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Banana'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Orange'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Tomato'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Banana'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Orange'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Tomato'),),
Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('Apple'),),
],
);
}
複製程式碼
具體效果如下:
通過GridView.builder()建立
該建立方式主要用於動態網格檢視或大資料的網格檢視。不同於GridView.count()的是其需要自己建立gridDelegate屬性
-
gridDelegate
網格代理物件,一般使用SliverGridDelegateWithFixedCrossAxisCount物件建立,可指定crossAxisCount、mainAxisSpacing、crossAxisSpacing和childAspectRatio等值。
-
itemCount
表示網格的單元格總數。
-
itemBuilder
其值為一個函式:Widget Function(BuildContext context, int index),實現該函式用於建立每個網格對應的Widget。
Widget getGridViewBuilder() {
return GridView.builder(
padding: EdgeInsets.all(15.0),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 30.0,
crossAxisSpacing: 15.0,
childAspectRatio: 1.5,
),
itemCount: 29,
itemBuilder: (buildContext, index) {
return Container(color: Colors.redAccent, alignment: Alignment.center, child: Text('第 ${index+1} 個Apple'),);
},
);
}
複製程式碼
具體效果如下:
佈局Widget
Container
Container是最常用的佈局Widget,表示一個容器,其主要屬性包括:
-
width
表示容器的寬度。
-
Height
表示容器的高度。
-
alignment
容器中內容的對齊方式,包括:Alignment.topLeft、Alignment.topCenter、Alignment.topRight、Alignment.centerLeft、Alignment.center、Alignment.centerRight、Alignment.bottomLeft、Alignment.bottomCenter、Alignment.bottomRight等。
-
color
容器的背景顏色。
-
padding
容器中內邊距。
-
decoration
容器背景裝飾,不能和color同時設定,設定此值時可以根據需要將容器設定為圓角矩形、特定邊框寬度和顏色等。
-
foregroundDecoration
容器內容的前景裝飾,和背景裝飾屬性類似,通常可以通過此屬性設定內容的半透明圖層。
-
margin
容器的外邊距
-
child
容器中的子Widget,只能設定一個子Widget。
Widget getContainer() {
return Container(
width: 200.0,
height: 200.0,
// color: Colors.blueAccent,
alignment: Alignment.center,
padding: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Colors.redAccent,
border: Border.all(color: Colors.blueAccent, width: 2.0, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(15.0),
),
foregroundDecoration: BoxDecoration(
color: Color(0x66000000),
borderRadius: BorderRadius.circular(15.0),
),
child: Text('Hello'),
margin: EdgeInsets.all(20.0),
);
}
複製程式碼
Padding
表示內邊距的Widget,可用於控制子Widget與外部Widget的邊距。主要有兩個屬性:
-
padding
用於邊距大小設定。
-
child
包含的子Widget。
Widget getPadding() {
return Padding(
padding: EdgeInsets.all(40.0),
child: Container(
width: 100,
height: 100,
alignment: Alignment.center,
color: Colors.redAccent,
child: Text('This is Padding widget demo'),
),
);
}
複製程式碼
Container和Padding例子程式碼執行的具體效果如下:
Center
用於使子Widget居中的Widget。包含三個屬性:
-
widthFactor
寬度因子,表示為該Widget寬度比子Widget寬度的倍數。
-
heightFactor
高度因子,表示為該Widget高度比子Widget高度的倍數。
-
child
包含的子Widget。
Widget getCenter() {
return Container(
color: Colors.grey,
child: Center(
widthFactor: 3,
heightFactor: 2,
child: Container(
width: 100,
height: 100,
alignment: Alignment.center,
color: Colors.redAccent,
child: Text('This is Center widget demo'),
),
),
);
}
複製程式碼
Align
控制子Widget對齊方式的Widget,包含以下屬性:
-
alignment
表示子Widget的對齊方式,包括Alignment.topLeft、Alignment.topCenter、Alignment.topRight、Alignment.centerLeft、Alignment.center、Alignment.centerRight、Alignment.bottomLeft、Alignment.bottomCenter、Alignment.bottomRight等,和Container的alignment屬性一樣。
-
widthFactor
寬度因子,同Center的widthFactor屬性一樣,其實Center widget就是繼承自Align widget,不過alignment值預設設定為了Alignment.center而已。
-
heightFactor
高度因子,同Center的heightFactor屬性一樣。
Widget getAlign() {
return Container(
color: Colors.green,
child: Align(
alignment: Alignment.centerLeft,
widthFactor: 3,
heightFactor: 2,
child: Container(
width: 100,
height: 100,
alignment: Alignment.center,
color: Colors.redAccent,
child: Text('This is Center widget demo'),
),
),
);
}
複製程式碼
Center和Align例子程式碼執行的具體效果如下:
Baseline
指定子Widget的基線,包含兩個主要屬性:
-
baseline
指定子Widget內容的基線位置,從外框也即是父控制元件的頂部位置開始定位基線位置。
-
baselineType
基線的型別,包括TextBaseline.ideographic和TextBaseline.alphabetic。
-
TextBaseline.alphabetic
對齊字母字元的水平線。
-
TextBaseline.ideographic
對齊表意字元的水平線。
-
Widget getBaseline() {
return Column(
children: <Widget>[
Container(
width: 200,
height: 100,
margin: EdgeInsets.all(100),
color: Colors.blueAccent,
child: Baseline(
baseline: 0,
baselineType: TextBaseline.alphabetic,
child: Text(
'Baseline type alphabetic',
style: TextStyle(fontSize: 20),
),
),
),
Container(
width: 200,
height: 100,
margin: EdgeInsets.all(100),
color: Colors.blueAccent,
child: Baseline(
baseline: 0,
baselineType: TextBaseline.ideographic,
child: Text(
'Baseline type ideographic',
style: TextStyle(fontSize: 20),
),
),
)
],
);
}
複製程式碼
SizedBox
指定大小的盒子佈局,可指定width和height寬高兩個屬性,其特點是可通過設定width=double.infinity和height=double.infinity來使盒子充滿父Widget寬高。
Widget getSizedBox() {
return SizedBox(
width: double.infinity,
height: 200,
child: Container(
color: Colors.redAccent,
child: Text('This is SizedBox widget demo'),
),
);
}
複製程式碼
Baseline和SizedBox例子程式碼執行的具體效果如下:
Row
行佈局,即水平佈局Widget,類似於安卓中android:orientation="horizontal"的LinearLayout佈局,主要屬性包括:
-
mainAxisAlignment
主軸方向上的對齊方式,此處就是水平方向對齊方式。
-
crossAxisAlignment
垂直於主軸方向上的對齊方式,此處就是垂直方向對齊方式。
-
mainAxisSize
主軸方向的大小,兩個可選值:
-
MainAxisSize.max
主軸方向最大值,一般為撐滿父控制元件。
-
MainAxisSize.min
主軸方向最小值,一般是根據子Widget算出的寬度。
-
-
textDirection
文字方向,子Widget的水平排列方向。兩個可選值:
-
TextDirection.rtl
根據子Widget的先後順序從右向左排。
-
TextDirection.ltr
根據子Widget的先後順序從左向右排。
-
-
verticalDirection
該屬性值主要用於Column Widget中,這裡使用預設即可,設定了也不起作用。
-
textBaseline
內容的基線型別。
-
children
子Widget集合。
Widget getRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
textDirection: TextDirection.rtl,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
const Text('This is Row Widget demo'),
const Icon(Icons.adb, size: 50,),
],
);
}
複製程式碼
Column
列布局,即垂直佈局Widget,類似於安卓中android:orientation="vertical"的LinearLayout佈局,屬性和Row的基本一樣,不同的是設定佈局順序時Row使用textDirection,而Column使用verticalDirection。
-
verticalDirection
子Widget的垂直排列方向。兩個可選值:
-
VerticalDirection.down
從上向下排列子Widget。
-
VerticalDirection.up
從下向上排列子Widget。
-
Widget getColumn() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
verticalDirection: VerticalDirection.down,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
const Text('This is Column Widget demo'),
const Icon(Icons.adb, size: 50,),
],
);
}
複製程式碼
Row和Column例子程式碼執行的具體效果如下:
總結
以上為常用的列表、網格Widget和佈局Widget使用方法,截止本篇結束我們已經介紹了絕大多數常用的Widget使用方法,後續在實際專案UI開發過程中我們會經常使用這些Widget,下一篇我們將為大家介紹自定義Widget的實現,用於滿足實戰中特殊UI需求。
說明:
文章轉載自對應的“Flutter程式設計指南”微信公眾號,更多Flutter相關技術文章開啟微信掃描二維碼關注微信公眾號獲取。