1.ListView 的基本使用
ListView 是一个盛放多个孩子的容器。我们从下面的例子开始介入:
1.1:三个构造
使用ListView构造方法
和Flex,Wrap类似,将子元素一个一个按顺序排列。
var caverStyle= TextStyle(fontSize: 18, shadows: [//文字样式
Shadow(
color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView(//ListView的构造方法
padding: EdgeInsets.all(8.0),//边距
children: [//孩子们
Container(
height: 50,
color: Color(0xffff0000),
child: Center(child: Text('红色',style: caverStyle,)),
),
Container(
height: 50,
color: Color(0xffFFFF00),
child: Center(child: Text('黄色',style: caverStyle,)),
),
Container(
height: 50,
color: Color(0xff00FF00),
child: Center(child: Text('绿色',style: caverStyle,)),
),
Container(
height: 50,
color: Color(0xff0000FF),
child: Center(child: Text('蓝色',style: caverStyle,)),
),
],
);
使用ListView.builder方法构造
使用builder方法对List或Map数据进行批量生成。
const colorMap = {//数据来源
0xffff0000: "红色",
0xffFFFF00: "黄色",
0xff00FF00: "绿色",
0xff0000FF: "蓝色",
};
var caverStyle= TextStyle(fontSize: 18, shadows: [//文字样式
Shadow(
color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView.builder(//使用builder方法进行构造
padding: EdgeInsets.all(8.0),
itemCount: colorMap.length,//条目的个数
itemBuilder: (BuildContext context, int index) {//条目构造器
return Container(
height: 50,
color: Color(colorMap.keys.toList()[index]),
child: Center(
child: Text(
'${colorMap.values.toList()[index]}',
style: caverStyle,
)),
);
});
使用ListView.separated方法构造
separated方法和builder类似,但是可以通过separatorBuilder属性创建分隔线。
const colorMap = {//数据来源
0xffff0000: "红色",
0xffFFFF00: "黄色",
0xff00FF00: "绿色",
0xff0000FF: "蓝色",
};
var caverStyle = TextStyle(fontSize: 18, shadows: [//文字样式
Shadow(color: Colors.white, offset: Offset(-0.5, 0.5), blurRadius: 0)
]);
var show = ListView.separated(//使用separated方法进行构造
padding: EdgeInsets.all(8.0),
itemBuilder: (context, index) {//条目构造器
return Container(
height: 50,
color: Color(colorMap.keys.toList()[index]),
child: Center(
child: Text(
'${colorMap.values.toList()[index]}',
style: caverStyle,
)),
);
},
separatorBuilder: (context, index) {//分隔线构造器
return Container();
},
itemCount: colorMap.length);
2.ListView进阶使用
2.1:完成条目的封装
比较简单,我也不分析这么布局了,直接上代码。
信息描述类
class PoemItem {
ImageProvider image;//图片
var title;//标题
var author;//作者
var summary;//摘要
PoemItem({this.image, this.title, this.author, this.summary});
}
条目的封装
typedef OnItemClickListener = void Function();
class PoemItemView extends StatelessWidget {
final PoemItem data;
final OnItemClickListener onItemClickListener;
PoemItemView({Key key, this.data, this.onItemClickListener})
: super(key: key);
@override
Widget build(BuildContext context) {
var headIcon = Container(//左边头部
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
offset: Offset(0.0, 0.0),
blurRadius: 3.0,
spreadRadius: 0.0,
),
],
),
width: 70,
height: 70,
child: Padding(
padding: EdgeInsets.all(3),
child: CircleAvatar(
backgroundImage: data.image,
),
));
var center = Column(//中间介绍
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(data.title,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Padding(
padding: EdgeInsets.only(top: 8),
child: Text(
"作者:${data.author}",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
),
],
);
var summary = Text(//尾部摘要
data.summary,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.grey, fontSize: 12),
);
var item = Row(//条目拼合
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(width: 10),
headIcon,
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: center,
),
Expanded(
child: summary,
),
SizedBox(width: 10),
],
);
var result = Card(//卡片化 事件监听
elevation: 5,
child: InkWell(
onTap: onItemClickListener,
child: Padding(
padding: EdgeInsets.all(10),
child: item,
)));
return result;
}
}
2.2:ListView的使用
代码语言:javascript复制在构造器构造条目时,使用数据对条目进行数据填充,侧达到数据展示效果
var data = [];
for (var i = 0; i < 20; i ) {
data.add(PoemItem(
image: AssetImage("images/wy_200x300.jpg"),
title: "$i:以梦为马",
author: "海子",
summary: "我要做远方的忠诚的儿子,和物质的短暂情人,和所有以梦为马的诗人一样,我不得不和烈士和小丑走在同一道路上"));
}
var show = ListView.builder(
padding: EdgeInsets.all(8.0),
itemCount: data.length, //条目的个数
itemBuilder: (BuildContext context, int index) {
return PoemItemView(//数据填充条目
data: data[index],
onItemClickListener: () {//事件响应
print(index);
},
);
});
2.3:分隔线的添加
代码语言:javascript复制这里现将Card组件去掉。separated可以很轻松的实现下划线分隔,并且容易改变长短,颜色 如果你愿意,也可以去定义分隔的组件,专门作为分隔线。而且还能使用索引进行个性化设计
var data = [];
for (var i = 0; i < 20; i ) {
data.add(PoemItem(
image: AssetImage("images/wy_200x300.jpg"),
title: "$i:以梦为马",
author: "海子",
summary: "我要做远方的忠诚的儿子,和物质的短暂情人,和所有以梦为马的诗人一样,我不得不和烈士和小丑走在同一道路上"));
}
var show = ListView.separated(
padding: EdgeInsets.all(8.0),
itemCount: data.length, //条目的个数
itemBuilder: (BuildContext context, int index) {
return PoemItemView(//数据填充条目
data: data[index],
onItemClickListener: () {//事件响应
print(index);
},
);
},
separatorBuilder: (BuildContext context, int index) {
return Padding(padding: EdgeInsets.only(left: 90),child: Divider(height: 1,color: Colors.orangeAccent,),);
},
);
2.4:一个ListView中不同的条目样式。
代码语言:javascript复制在抽取条目时,可以定义一个type属性,条目样式由Widget自身决定。
var random = Random();
var data = [];
var strs = [
"我是要成为编程之王的男人,你是要成为编程之王的女人",
"凭君莫话封侯事,一将功成万骨枯。你觉得如何?",
"在苍茫的大海上,狂风卷积着乌云,在乌云和大海之间,海燕像黑色的闪电,在高傲的飞翔。"
];
for (var i = 0; i < 20; i ) {
data.add(ChartItem(
headIcon: AssetImage(
i.isEven ? "images/wy_200x300.jpg" : "images/icon_head.png"),
text: strs[random.nextInt(strs.length)],
type: i.isEven ? ChartType.left : ChartType.right));
}
var show = ListView.builder(
itemCount: data.length, //条目的个数
itemBuilder: (BuildContext context, int index) {
return ChartWidget(//数据填充条目
chartItem: data[index],
);
},
);
代码语言:javascript复制比如这里的ChartItem,本身定义了ChartType,在实现ChartWidget的时候,根据类型进行生成相应Widget,从而达到多种样式的效果。
enum ChartType { right, left }
class ChartItem {
ImageProvider headIcon;
double maxWith;
ChartType type;
String text;
ChartItem({this.headIcon, this.text,this.maxWith = 250,this.type=ChartType.right});
}
class ChartWidget extends StatelessWidget {
final ChartItem chartItem;
ChartWidget({Key key, this.chartItem}) : super(key: key);
@override
Widget build(BuildContext context) {
switch (chartItem.type) {
case ChartType.right:
return _buildRight();
break;
case ChartType.left:
return _buildLeft();
break;
}
}
3.ListView滑动控制器(上拉刷新和下拉更新)
3.1:滑动控制器ScrollController的使用
代码语言:javascript复制class _ListViewPageState extends State {
ScrollController _scrollController = ScrollController();//定义变量及初始化
@override
void initState() {
super.initState();
_scrollController.addListener(() {//添加监听
print("滑动了:${_scrollController.position.pixels},
离顶部高:${_scrollController.position.maxScrollExtent}");
});
}
@override
void dispose() {
_scrollController.dispose();//销毁控制器
super.dispose();
}
@override
Widget build(BuildContext context) {
//略同...
var show = ListView.builder(
controller: _scrollController, //使用ScrollController
//略同...
);
}
}
3.2:上拉刷新
代码语言:javascript复制内置组件:RefreshIndicator,包裹一下即可
return RefreshIndicator(child: show, onRefresh: _onRefresh//使用RefreshIndicator
}
bool isLoading = false;
Future _onRefresh() async {//下拉刷新,异步延迟三秒
if (isLoading) {
return;
}
await Future.delayed(Duration(seconds: 3), () {
setState(() {
isLoading = false;
});
});
}
3.3:下拉加载更多
代码语言:javascript复制_scrollController.addListener(() {
if (_scrollController.position.pixels ==//说明滑到底部
_scrollController.position.maxScrollExtent) {
_loadMore();
}
});
bool isLoaded = false;
Future _loadMore() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
isLoaded=true;
});
});
}
var show = ListView.builder(
controller: _scrollController,
itemCount: data.length 1, //条目的个数
itemBuilder: (BuildContext context, int index) {
if (index == data.length) {
return Offstage(//使用Offstage控制显隐
offstage: isLoaded,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Center(
child: CircularProgressIndicator(),
),
));
} else {
return ChartWidget(
//数据填充条目
chartItem: data[index],
);
}
});
4. physics属性
physics对应ScrollPhysics类,其下有6个子类
FixedExtentScrollPhysics()
和NeverScrollableScrollPhysics
ListView无法滑动
PageScrollPhysics()
会根据你的滑动来自动调节,比如你滑的距离小,则自动还原,
到达一定大小,也会自动下滑一个条目
BouncingScrollPhysics()
顶底会有而外空间,让富有弹性
ClampingScrollPhysics()
和AlwaysScrollableScrollPhysics()
顶底会有蓝色阴影
另外还有
reverse属性控制数据是否反序
,scrollDirection控制ListView的方向