在之前講
Layout Widget
的文章中,我們掌握了基于不同的場景適當?shù)倪x擇不同的Widget來完成我們的布局要求茬射,但是關于長列表的數(shù)據(jù)展示我們并沒有做展開介紹,而長列表的身影幾乎出現(xiàn)在日常生活中的任意一款APP中,鑒于它的重要性焕檬,所以我想單獨作為一個章節(jié)來講解長列表Widget---ListView&GirdView
宴霸。
1.ListView
1.1 ListView簡單列表
看下ListView的構造方法囱晴,然后我們用listview來完成一個簡單列表
ListView({
Key key,
Axis scrollDirection: Axis.vertical,//滾動方向
bool reverse: false,//是否反向顯示數(shù)據(jù)
ScrollController controller,
bool primary,
ScrollPhysics physics,//物理滾動
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
this.itemExtent,//item有效范圍
bool addAutomaticKeepAlives: true,//自動保存視圖緩存
bool addRepaintBoundaries: true,//添加重繪邊界
List<Widget> children: const <Widget>[],
})
上述效果圖樣例代碼
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "ListView",
home: new MyApp(),
));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: ListView(
scrollDirection: Axis.vertical, //控制列表方向
children: <Widget>[
new Container(
width: 100.0,
height: 100.0,
color: Colors.lightBlue,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.red,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.deepPurple,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.yellow,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.lightBlue,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.red,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.deepPurple,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.lightBlue,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.red,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.deepPurple,
),
new Container(
width: 100.0,
height: 100.0,
color: Colors.lightBlue,
),
],
));
}
}
上述代碼中我們利用ListView做了一個簡單的長列表布局,通過給children: <Widget>[]
傳入我們要展示的子Widget來完成列表渲染瓢谢,理論上我們可以傳入任意多的子Widget畸写,但是這點使用起來跟Column
沒有太大差別,這顯然是不符合我們的預期的氓扛,因為我們在使用ListView展示長列表布局的時候枯芬,大多數(shù)情況下我們是不知道長列表一共有多少個元素,即使是能知道采郎,我們重復性的把每個相似的布局都寫一遍千所,也幾乎讓人崩潰。
沒錯蒜埋,F(xiàn)lutter肯定給我們提供了像原生Android寫Adapter一樣的方式淫痰,我們可以提前寫好公共的Item布局,然后通過ListView.builder()或者ListView.custom()
方式自動生成長列表整份,ListView.builder()
和ListView.custom()
的用法基本相同待错,只不過custom可以根據(jù)自己的需要控制Item顯示方式,如Item顯示大小烈评。
1.2 可復用的ListView長列表
下面我?guī)Т蠹乙黄鹂聪翷istView.builder()的構造方法火俄,然后使用ListView.builder寫個簡單的樣式代碼,至于ListView.custom的用法我會在下面介紹GridView的時候講到讲冠,讀者可參考Listview.bulider自行測試瓜客。
ListView.builder({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
this.itemExtent,
@required IndexedWidgetBuilder itemBuilder,//item構建者
int itemCount,//item數(shù)量
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
})
從ListView.bulider的構造方法我們可以看出,它只比上述我們直接使用的ListView的構造方法多了兩個參數(shù),也正是這兩個參數(shù)簡化了我們對長列表的操作
itemCount:
:被展示的Item的數(shù)量
itemBuilder
:被展示的Item的構造者(這里讀者可以它類比成原生Android的Adapter)
下面我們來看下效果圖:
樣例代碼
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "ListView",
home: new MyApp(),
));
}
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyState();
}
class MyState extends State {
List<ItemEntity> entityList = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 30; i++) {
entityList.add(ItemEntity("Item $i", Icons.accessibility));
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ItemView(entityList[index]);
},
itemCount: entityList.length,
));
}
}
/**
* 渲染Item的實體類
*/
class ItemEntity {
String title;
IconData iconData;
ItemEntity(this.title, this.iconData);
}
/**
* ListView builder生成的Item布局忆家,讀者可類比成原生Android的Adapter的角色
*/
class ItemView extends StatelessWidget {
ItemEntity itemEntity;
ItemView(this.itemEntity);
@override
Widget build(BuildContext context) {
return Flex(
direction: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(itemEntity.iconData), title: Text(itemEntity.title),subtitle: Text('長列表')),
SizedBox(
height: 0.2,
child: Container(
color: Colors.black,
),
)
],
);
}
}
上述代碼中的邏輯讀者大部分都可以自解的犹菇,我就不多做贅述了,下面我們進入本篇分享的第二部分芽卿,關于GridView部分的講解揭芍。
2.GridView
跟原生Android一樣,GridView
滿足了我們所有使用表格布局的場景卸例,當然如果GridView在每行或者每列都只顯示一個Item的時候又相當于ListView的使用場景称杨。但是回到Flutter上GridView
的用法又跟ListView使用類似,可以直接new對象的方式生成簡單的表格布局筷转,也可以像ListView那樣通過builder()和custom()
方法來創(chuàng)建可復用的對象
構造方法
GridView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
@required this.gridDelegate, //控制GridView顯示方式
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
List<Widget> children: const <Widget>[],
})
上面提到GridView跟ListView使用方法類似姑原,但是GridView不同于ListView的是它可以在一行或者一列顯示多個Item,所以GridView的構造方法對比ListView多了一個gridDelegate
參數(shù)呜舒,來配置一行(列)有幾個Item和Item的間隔锭汛。
gridDelegate參數(shù)說明
gridDelegate
可接收兩種參數(shù)類型:
SliverGridDelegateWithFixedCrossAxisCount
可以直接指定每行(列)顯示多少個ItemSliverGridDelegateWithMaxCrossAxisExtent
會根據(jù)GridView的寬度和你設置的每個的寬度來自動計算沒行顯示多少個Item
先來看下GridView的效果圖,關于gridDelegate
的區(qū)別我在代碼里做了注釋講解袭蝗,這里就不在多贅述了讀者可結合代碼自行理解唤殴。
效果圖
樣例代碼
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "ListView",
home: new MyApp(),
));
}
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyState();
}
class MyState extends State {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: new GridView(
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 3, //固定顯示三個
// mainAxisSpacing: 10,
// crossAxisSpacing: 10),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100, //根據(jù)maxCrossAxisExtent的值對比屏幕的真實寬度,決定一行或者一列顯示多少個Item
mainAxisSpacing: 10,
crossAxisSpacing: 10),
children: <Widget>[
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
Container(
child: Icon(Icons.adb, size: 60),
color: Colors.deepOrangeAccent),
],
));
}
}
在本篇分享的第一部分我們介紹ListView的時候提到到腥,為了復用Item布局朵逝,我們可以通過builder()或者custom來生成Item布局,在ListView中我們使用的是builder()
的方式生成的可復用的布局乡范,在gridView中我?guī)Т蠹沂褂孟?code>custom()配名,其實listView跟GridView使用類似,無非就是布局排列不同而已晋辆。
效果圖
樣例代碼
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "ListView",
home: new MyApp(),
));
}
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyState();
}
class MyState extends State {
List<ItemEntity> entityList = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 30; i++) {
entityList.add(ItemEntity("Item $i", Icons.accessibility));
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("GridView"),
),
body: GridView.custom(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ItemView(entityList[index]);
},
childCount: entityList.length,
)));
}
}
/**
* 渲染Item的實體類
*/
class ItemEntity {
String title;
IconData iconData;
ItemEntity(this.title, this.iconData);
}
/**
* GridView builder生成的Item布局渠脉,讀者可類比成原生Android的Adapter的角色
*/
class ItemView extends StatelessWidget {
ItemEntity itemEntity;
ItemView(this.itemEntity);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Flex(
direction: Axis.vertical,
children: <Widget>[
Icon(
itemEntity.iconData,
size: 60,
),
Text(itemEntity.title),
],
),
onTap: () {
Scaffold.of(context).showSnackBar(
new SnackBar(content: Text("點擊了${itemEntity.title}")));
},
);
}
}
總結
通過本篇博文我們了解到ListView跟GridView都可以直接用new對象的方式生成列表布局,一個用于表格布局栈拖,另一個用于長列表布局连舍,也可以使用new 或者builder()和custom()方法來創(chuàng)建可復用對象,從而擴展了ListView跟GridView的靈活性涩哟,就像我們原生Android一樣索赏,把可復用的布局抽象成Adapter的形式,但是或許你總覺得關于列表還少點什么贴彼,下拉刷新潜腻?加載更多?