基本信息
ListView({
Key key,
Axis scrollDirection: Axis.vertical, //滚动方向
bool reverse: false, //是否翻转数据
ScrollController controller, //控制器
bool primary,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsetsGeometry padding,
double itemExtent,
bool addAutomaticKeepAlives: true,
bool addRepaintBoundaries: true,
bool addSemanticIndexes: true,
double cacheExtent,
List<Widget> children: const [],
int semanticChildCount,
DragStartBehavior dragStartBehavior: DragStartBehavior.start
})
在创建ListView.builder时,需要传入两个参数,一个列表的初始长度,一个itemBuilder函数。ListVIew还支持基于Sliver的延迟构建模型。
基于Sliver的延迟构建模式:通常可滚动组件的子组件可能会非常多,占用的总高度也会非常大,如果要一次性将子组件全部构建出将会导致性能差的问题出现,为此,Flutter中提出一个Sliver(中文为"薄片"的意思)概念,如果一个可滚动组件支持Sliver模型,那么该滚动组件可以将子组件分成好多个薄片(Sliver),只有当Sliver出现在视口时才会去构建它,这种模型也成为"基于Sliver的延迟构建模型"。可滚动组件中有很多都支持基于Sliver的延迟构建模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView
下拉刷新指示器
RefreshIndicator({
Key key,
@required Widget child, //宽度
double displacement: 40.0, //高度
@required RefreshCallback onRefresh, //刷新回调
Color color, //圆圈颜色
Color backgroundColor, //背景颜色
ScrollNotificationPredicate notificationPredicate: defaultScrollNotificationPredicate,
String semanticsLabel, 语义文本
String semanticsValue
})
下拉刷新和上拉加载
import 'package:flutter/material.dart';
class TestList extends StatefulWidget {
@override
_TestListState createState() => _TestListState();
}
class _TestListState extends State<TestList> {
final List<String> list = [];
int page = 0;
ScrollController _controller = ScrollController();
@override
void initState() {
_getData();
_controller.addListener((){ //当前位置==最大滑动范围,滑到底了
if(_controller.position.pixels == _controller.position.maxScrollExtent){
if(page < 3){
_retrieveData();
}
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '轻松学',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: Text('测试')),
body: RefreshIndicator(
onRefresh: _onRefresh, //下拉刷新回调
color: Colors.red,
//backgroundColor: Colors.blue,
displacement: 40, //指示器显示时距顶部位置
child: ListView.separated(
controller: _controller,
physics: BouncingScrollPhysics(),//列表滑动到边界时,显示iOS的弹出效果
itemBuilder: (BuildContext context, int i){ //列表构造器
if(i == list.length){
if(page < 3){
return Container(
padding: EdgeInsets.only(top: 10, bottom: 10),
alignment: Alignment.center,
child: SizedBox(
child: CircularProgressIndicator(strokeWidth: 2,),
height: 20,
width: 20,
)
);
} else {
return Container(
padding: EdgeInsets.only(top: 10, bottom: 10),
alignment: Alignment.center,
child: Text(
'~我是底线~',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.blue,
)
),
);
}
} else {
return ListTile(
title: Text('${list[i]}'),
leading: Icon(Icons.home),
);
}
},
separatorBuilder:(BuildContext context, int i){
return Divider(color: Colors.blue);
},
itemCount: list.length+1 // 注意多加一个,loading的位置
)
)
),
);
}
void _getData(){
for(var i= 0; i < 20; i++){
list.insert(i, "第${list.length}条原始数据");
}
}
Future<void> _onRefresh()async{
await Future.delayed(Duration(seconds: 2)).then((e){ //
setState(() {
page = 0;
list.clear();
for(var i= 0; i < 20; i++){
list.insert(i, "第${list.length}条原始数据");
}
});
});
}
Future<void> _retrieveData()async{
await Future.delayed(Duration(seconds: 2)).then((e){ //
setState(() {
page++;
for(var i= 0; i < 20; i++){
list.insert(list.length, "第${list.length}条原始数据");
}
});
});
}
@override
void dispose() {
super.dispose();
}
}
下拉刷新,使用RefreshIndicator组件在回调onRefresh中实现,上拉加载使用ScrollController去判断滚动条位置
注意: itemCount多加一个,给loading占给位置。
嵌套的 ListView 无法滚动的问题
可滑动控件都有这两个属性,给子滑动部件设置上这两个参数,即可办到子ListView跟随父ListView滑动
shrinkWrap: true, //解决无限高度问题 physics:NeverScrollableScrollPhysics(),//禁用滑动事件