ListView
先看下如下截圖
以上效果圖的程式碼,是從flutter
官方demoflutter_gallery
內copy的部分程式碼。
首先,首先定義一個列表,程式碼如下
List<String> items = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
];
複製程式碼
然後,通過上面的定義的列表資料,現在構建ListView
的子Widget資料,程式碼如下
Iterable<Widget> listTiles = items
.map<Widget>((String item) => buildListTile(context, item));
Widget buildListTile(BuildContext context, String item) {
Widget secondary = const Text(
'Even more additional list item information appears on line three.',
);
return ListTile(
isThreeLine: true,
leading: ExcludeSemantics(child: CircleAvatar(child: Text(item))),
title: Text('This item represents $item.'),
subtitle: secondary,
trailing: Icon(Icons.info, color: Theme.of(context).disabledColor),
);
}
複製程式碼
最後,將生成的子Widget資料填充到ListView
內,程式碼如下
ListView(
children: listTiles.toList(),
)
複製程式碼
以上程式碼,就能完成最上面截圖的效果。下面主要對ListTile
做一下介紹
ListTile
ListTile
是Flutter
給我們準備好的widget提供非常常見的構造和定義方式,包括文字,icon,點選事件,一般是能夠滿足基本列表需求。
建構函式
ListTile({
Key key,
this.leading,
this.title,
this.subtitle,
this.trailing,
this.isThreeLine = false,
this.dense,
this.contentPadding,
this.enabled = true,
this.onTap,
this.onLongPress,
this.selected = false,
})
複製程式碼
屬性
使用
ListTile(
//展示三行
isThreeLine: true,
//前置圖示
leading: ExcludeSemantics(child: CircleAvatar(child: Text(item))),
//標題
title: Text('This item represents $item.'),
//副標題
subtitle: secondary,
//後置圖示
trailing: Icon(Icons.info, color: Theme.of(context).disabledColor),
)
複製程式碼
效果
ListView.builder
ListView.builder適合列表項比較多(或者無限)的情況,因為只有當子Widget真正顯示的時候才會被建立。
將上面列表填充的程式碼修改為ListView.builder
,程式碼如下所示
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return buildListTile(context, items[index]);
})
複製程式碼
執行結果如下圖所示
ListView.separated
ListView.separated
可以生成列表項之間的分割器,它比ListView.builder多了一個separatorBuilder引數,該引數是一個分割器生成器。
將上面列表填充的程式碼修改為ListView.separated
,程式碼如下所示
ListView.separated(
itemBuilder: (BuildContext context, int index) {
return buildListTile(context, items[index]);
},
separatorBuilder: (BuildContext context, int index) {
return index % 2 == 0 ? divider1 : divider2;
},
itemCount: items.length
)
複製程式碼
執行結果如下圖所示
例項:Listview下拉重新整理 上拉載入更多
下面實現首次進入頁面,載入資料,下拉能重新整理頁面資料,上拉能載入更多資料。
下拉重新整理
下拉重新整理,用到的是Flutter
自帶的RefreshIndicator
Widget,ListView
主要用ListView.builder
進行實現。程式碼如下所示
RefreshIndicator(
key: refreshIndicatorKey,
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return buildListTile(context, list[index]);
},
),
onRefresh: onRefresh)
複製程式碼
實現下拉重新整理,主要需要實現RefreshIndicator
的onRefresh
屬性,程式碼如下所示
Future<Null> onRefresh() async {
return Future.delayed(Duration(seconds: 2)).then((e) {
list.addAll(items);
setState(() {
//重新構建列表
});
});
}
複製程式碼
主要實現延遲2s載入資料,在重新重新整理列表。
首次進入頁面,Loading
狀態的實現實現如下面程式碼所示
void showRefreshLoading() async {
await Future.delayed(const Duration(seconds: 0), () {
refreshIndicatorKey.currentState.show().then((e) {});
return true;
});
}
複製程式碼
當Loading
完之後會觸發RefreshIndicator
的onRefresh
屬性,到此,下拉重新整理已經實現完畢。
執行效果如下圖所示
上拉載入更多
上拉載入需要監聽ListView
的滾動事件,當滾動事件與底部小於50並且有更多資料載入時,才會觸發載入更多的邏輯,如下面程式碼所示
scrollController.addListener(() {
var position = scrollController.position;
// 小於50px時,觸發上拉載入;
if (position.maxScrollExtent - position.pixels < 50 &&
!isNoMore) {
loadMore();
}
});
void loadMore() async {
if (!isLoading) {
//重新整理載入狀態
isLoading = true;
setState(() {});
Future.delayed(Duration(seconds: 2)).then((e) {
list.addAll(items);
//取消載入狀態,並提示暫無更多資料
isLoading = false;
isNoMore = true;
setState(() {
//重新構建列表
});
});
}
}
複製程式碼
檢視層的程式碼,當需要處理載入更多的邏輯時,ListView
的itemCount
屬性需要進行加1,用來填充載入更多的檢視。如下面程式碼所示
int getListItemCount() {
int count = list.length;
if (isLoading || isNoMore) {
count += 1;
}
return count;
}
複製程式碼
ListView
的itemBuilder
屬性,載入更多的檢視程式碼如下所示
Widget builderMore() {
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
isNoMore
? Text("")
: SizedBox(
width: 20.0,
height: 20.0,
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor: AlwaysStoppedAnimation(Colors.black)),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 15.0),
child: Text(
isNoMore ? "沒有更多資料" : "載入中...",
style: TextStyle(fontSize: 16.0),
),
),
],
),
),
);
}
複製程式碼
對RefreshIndicator
程式碼做如下修改
RefreshIndicator(
key: refreshIndicatorKey,
child: ListView.builder(
controller: scrollController,
itemCount: getListItemCount(),
itemBuilder: (context, index) {
return builderItem(context, index);
},
),
onRefresh: onRefresh)
Widget builderItem(BuildContext context, int index) {
if (index < list.length) {
return buildListTile(context, list[index]);
}
return builderMore();
}
複製程式碼
執行程式碼 載入中的效果如下圖所示
沒有更多資料的效果如下圖所示