個(gè)人博客
ListView
先看下如下截圖
以上效果圖的代碼,是從
flutter
官方demoflutter_gallery
內(nèi)copy的部分代碼距芬。首先涝开,首先定義一個(gè)列表,代碼如下
List<String> items = <String>[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
];
然后框仔,通過(guò)上面的定義的列表數(shù)據(jù)舀武,現(xiàn)在構(gòu)建ListView
的子Widget數(shù)據(jù),代碼如下
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數(shù)據(jù)填充到ListView
內(nèi)银舱,代碼如下
ListView(
children: listTiles.toList(),
)
以上代碼,就能完成最上面截圖的效果跛梗。下面主要對(duì)ListTile
做一下介紹
ListTile
ListTile
是Flutter
給我們準(zhǔn)備好的widget提供非常常見(jiàn)的構(gòu)造和定義方式寻馏,包括文字,icon核偿,點(diǎn)擊事件诚欠,一般是能夠滿(mǎn)足基本列表需求。
構(gòu)造函數(shù)
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,
//前置圖標(biāo)
leading: ExcludeSemantics(child: CircleAvatar(child: Text(item))),
//標(biāo)題
title: Text('This item represents $item.'),
//副標(biāo)題
subtitle: secondary,
//后置圖標(biāo)
trailing: Icon(Icons.info, color: Theme.of(context).disabledColor),
)
效果
ListView.builder
ListView.builder適合列表項(xiàng)比較多(或者無(wú)限)的情況宪祥,因?yàn)橹挥挟?dāng)子Widget真正顯示的時(shí)候才會(huì)被創(chuàng)建聂薪。
將上面列表填充的代碼修改為ListView.builder
家乘,代碼如下所示
ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return buildListTile(context, items[index]);
})
運(yùn)行結(jié)果如下圖所示
ListView.separated
ListView.separated
可以生成列表項(xiàng)之間的分割器蝗羊,它比ListView.builder多了一個(gè)separatorBuilder參數(shù),該參數(shù)是一個(gè)分割器生成器仁锯。
將上面列表填充的代碼修改為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
)
運(yùn)行結(jié)果如下圖所示
實(shí)例:Listview下拉刷新 上拉加載更多
下面實(shí)現(xiàn)首次進(jìn)入頁(yè)面,加載數(shù)據(jù)业崖,下拉能刷新頁(yè)面數(shù)據(jù)野芒,上拉能加載更多數(shù)據(jù)。
下拉刷新
下拉刷新双炕,用到的是Flutter
自帶的RefreshIndicator
Widget,ListView
主要用ListView.builder
進(jìn)行實(shí)現(xiàn)狞悲。代碼如下所示
RefreshIndicator(
key: refreshIndicatorKey,
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return buildListTile(context, list[index]);
},
),
onRefresh: onRefresh)
實(shí)現(xiàn)下拉刷新,主要需要實(shí)現(xiàn)RefreshIndicator
的onRefresh
屬性妇斤,代碼如下所示
Future<Null> onRefresh() async {
return Future.delayed(Duration(seconds: 2)).then((e) {
list.addAll(items);
setState(() {
//重新構(gòu)建列表
});
});
}
主要實(shí)現(xiàn)延遲2s加載數(shù)據(jù)摇锋,在重新刷新列表丹拯。
首次進(jìn)入頁(yè)面,Loading
狀態(tài)的實(shí)現(xiàn)實(shí)現(xiàn)如下面代碼所示
void showRefreshLoading() async {
await Future.delayed(const Duration(seconds: 0), () {
refreshIndicatorKey.currentState.show().then((e) {});
return true;
});
}
當(dāng)Loading
完之后會(huì)觸發(fā)RefreshIndicator
的onRefresh
屬性荸恕,到此乖酬,下拉刷新已經(jīng)實(shí)現(xiàn)完畢。
運(yùn)行效果如下圖所示
上拉加載更多
上拉加載需要監(jiān)聽(tīng)ListView
的滾動(dòng)事件融求,當(dāng)滾動(dòng)事件與底部小于50并且有更多數(shù)據(jù)加載時(shí)咬像,才會(huì)觸發(fā)加載更多的邏輯,如下面代碼所示
scrollController.addListener(() {
var position = scrollController.position;
// 小于50px時(shí)生宛,觸發(fā)上拉加載县昂;
if (position.maxScrollExtent - position.pixels < 50 &&
!isNoMore) {
loadMore();
}
});
void loadMore() async {
if (!isLoading) {
//刷新加載狀態(tài)
isLoading = true;
setState(() {});
Future.delayed(Duration(seconds: 2)).then((e) {
list.addAll(items);
//取消加載狀態(tài),并提示暫無(wú)更多數(shù)據(jù)
isLoading = false;
isNoMore = true;
setState(() {
//重新構(gòu)建列表
});
});
}
}
視圖層的代碼茅糜,當(dāng)需要處理加載更多的邏輯時(shí)七芭,ListView
的itemCount
屬性需要進(jìn)行加1,用來(lái)填充加載更多的視圖蔑赘。如下面代碼所示
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 ? "沒(méi)有更多數(shù)據(jù)" : "加載中...",
style: TextStyle(fontSize: 16.0),
),
),
],
),
),
);
}
對(duì)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();
}
運(yùn)行代碼
加載中的效果如下圖所示
沒(méi)有更多數(shù)據(jù)的效果如下圖所示