文章目錄
Flutter ListView
列表佈局在手機上是最最常用的控件了。
Android上的RecycleView尤其的強大。
Flutter中也給我們提供了ListView,不過就目前的體驗來看,性能跟原生的ListView或RecycleView比還是有一點差距的。滑動起來還是略卡。
下面我們來看一下ListView的相關知識
繼承關係
可以看到,ListView和GridView都繼承自BoxScrollView,因此,他們的屬性差不多,用法也相似。
構造方法
ListView({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
this.itemExtent,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
List<Widget> children = const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
})
常用屬性
屬性 | 值類型 | 說明 |
---|---|---|
scrollDirection | Axis | 設置滾動的方向,horizontal(水平)或vertical(垂直) |
reverse | bool | 是否翻轉 |
itemExtent | double | 滾動方向子控件的長度,垂直方向即爲高度,水平方向即爲寬度 |
controller | ScrollController | 用來控制滾動位置及監聽滾動事件 |
shrinkWrap | bool | 是否根據子widget的總長度來設置ListView的長度 |
padding | EdgeInsetsGeometry | 間距 |
children | List | 子控件 |
常用屬性都比較簡單,沒啥好說的,我們來直接用一下
ListView(
children: List.generate(30, (index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: Text("item${index}"),
);
}),
);
效果圖:
這裏我們要注意一下itemExtent屬性
itemExtent
該屬性用來控制子控件在滾動方向上的長度,所以它跟scrollDirection是密切相關的。
例如:
當滾動方向爲垂直方向時,那麼itemExtent就是控制子控件的高度
當滾動方向爲水平方向時,那麼itemExtent就是控制子控件的寬度
示例:我們在垂直方向上設置一下itemExtent
ListView(
scrollDirection: Axis.vertical,
itemExtent: 60,
children: List.generate(50, (index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: Text("item${index}"),
);
}),
);
圖示如下:此時,itemExtent控制的是子控件的高度
我們更改一下滾動方向爲水平:
ListView(
scrollDirection: Axis.horizontal,
itemExtent: 60,
children: List.generate(50, (index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: Text("item${index}"),
);
}),
);
此時,itemExtent控制的就是子控件的寬度了
圖示:
Flutter ListView加載更多/異步加載(ListView.builder)
構造方法適合在數據較少且固定的情況下使用,我們在開發過程中一般數據都是從網絡獲取的,並且基本都有分頁的需求,此時,我們就需要動態的加載數據了。
跟GridView一樣,ListView提供了ListView.builder方法供我們動態加載數據時使用,且使用方法基本一致。
首先看看源碼:
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,
int itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
})
屬性跟構造方法中的屬性差不多,我們主要來看看itemCount和itemBuilder
itemCount表示列表的數量,一般都是集合的長度
itemBuilder是列表項構造器,返回一個Widget
這裏我就直接用了
import 'package:flutter/material.dart';
/*
* 列表控件
*
* */
class ListViewWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
itemExtent: 60,
children: List.generate(50, (index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: Text("item${index}"),
);
}),
);
}
}
class ListViewBuilder extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ListViewBuilder();
}
}
class _ListViewBuilder extends State<ListViewBuilder> {
/*初始項爲50個*/
List<int> indexs = List.generate(50, (index) {
return index;
});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: indexs.length,
itemBuilder: (context, index) {
/*加載到底部時且集合數量小於100的話,獲取更多數據*/
if (index==indexs.length-1&&indexs.length < 100) {
_getMoreData(index);
}
return Text("${index}");
});
}
void _getMoreData(int index) {
Future.delayed(Duration(milliseconds: 300)).then((e) {
setState(() {
/*往集合裏添加10條數據*/
indexs.addAll(List.generate(10, (i) {
return index + i;
}));
});
});
}
}
圖示:
初始值集合中只有50條數據,然後每次增加10條
Flutter ListView分割線(ListView.separated)
通常情況下,我們的列表之間都有分割線,便於用戶區分,我們既可以在子控件中手動添加分割線的樣式,例如一開始的構造方法那樣,但是那樣會造成分割線重疊的情況。
而ListView.separated可以讓我們方便的給列表加上分割線。
我們先來看一下源碼:
ListView.separated({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required IndexedWidgetBuilder itemBuilder,
@required IndexedWidgetBuilder separatorBuilder, //分割線
@required int itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
})
可以看到屬性中多了一個separatorBuilder
separatorBuilder即爲分割線構建器
下面我們給上面的列表加上灰色分割線:
import 'package:flutter/material.dart';
/*
* 列表控件
*
* */
class ListViewWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
itemExtent: 60,
children: List.generate(50, (index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: Text("item${index}"),
);
}),
);
}
}
class ListViewBuilder extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ListViewBuilder();
}
}
class _ListViewBuilder extends State<ListViewBuilder> {
/*初始項爲50個*/
List<int> indexs = List.generate(50, (index) {
return index;
});
@override
Widget build(BuildContext context) {
/*灰色分割線*/
var divider = Divider(
color: Colors.grey,
);
return ListView.separated(
padding: EdgeInsets.all(10),
itemCount: indexs.length,
separatorBuilder: (context, index) {
return divider;
},
itemBuilder: (context, index) {
/*加載到底部時且集合數量小於100的話,獲取更多數據*/
if (index == indexs.length - 1 && indexs.length < 100) {
_getMoreData(index);
}
return Text("${index}");
});
}
void _getMoreData(int index) {
Future.delayed(Duration(milliseconds: 300)).then((e) {
setState(() {
/*往集合裏添加10條數據*/
indexs.addAll(List.generate(10, (i) {
return index + i;
}));
});
});
}
}
好了 Flutter ListView的基本用法大概就是這樣
如果你覺得本文對你有幫助,麻煩動動手指頂一下,算是對本文的一個認可。也可以關注我的 Flutter 博客專欄,我會不定期的更新,如果文中有什麼錯誤的地方,還望指正,轉載請註明轉自喻志強的博客 ,謝謝!