Flutter练习demo
Listview 常用属性
reverse 和 shrinkWrap使用注意
- 正常Listview 内容不够一屏(不设置 reverse 和 shrinkWrap属性)
- reverse = true
默认false
scrollDirection = Axis.vertical false:布局从上倒下 true:从下往上
scrollDirection = Axis.horizontal = 默认 false:布局从左倒右 true:从右往左 - reverse=true shrinkWrap=true
shrinkWrap:默认false 滚动方向的滚动视图内容是否应该由正在查看的内容所决定
三图对比可以验证 shrinkWrap=true,滚动方向的滚动视图内容是否应该由正在查看的内容所决定
ListTitle常用属性
Listview和ListTitle的简单使用
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class ListViewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.home),
title: Text("ListView"),
),
body: ListView(
scrollDirection: Axis.vertical,
// reverse: true,
//vertical = 默认 false:布局从上倒下 true:从下往上
//horizontal = 默认 false:布局从左倒右 true:从右往左
// shrinkWrap: true,
padding: EdgeInsets.all(20),
children: <Widget>[
ListTile(
enabled: false, // false onTap onLongPress失效
onTap: () {
_toOnTap();
},
onLongPress: () {
_toLongPress();
},
title: Text("ListTitle"),
subtitle: Text("我是ListTitle的副标题"),
leading: Icon(
Icons.save,
color: Color(0x99ff22ee),
),
trailing: Icon(Icons.search),
),
Center(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(150)),
color: Colors.blue,
image: DecorationImage(
image: AssetImage('images/s.jpg'), fit: BoxFit.cover)),
width: 100,
height: 100,
)),
Center(
child: ClipOval(
child: Image.asset(
'images/x.jpg',
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
),
Center(
child: ClipOval(
child: Image.file(
File(
'/storage/emulated/0/Android/data/c.s.sflutter/files/a.jpg'),
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
),
Center(
child: ClipOval(
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564720497900&di=e563c915685bceb398e4692b4ebab4e0&imgtype=jpg&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D551180330%2C2986440005%26fm%3D214%26gp%3D0.jpg',
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
),
],
),
),
);
}
}
_toOnTap() {
print('ListTitle = _toOnTap');
}
_toLongPress() {
print('ListTitle = _toLongPress');
}
ListView动态加载Item
方式1
import 'package:flutter/material.dart';
class DongtaiListViewPage extends StatelessWidget {
List<Widget> _getList() {
List<Widget> list = new List();
for (var i = 0; i < 10; i++) {
list.add(ListTile(
title: Text("ListTile = $i"), subtitle: Text("subtitle = $i")));
}
return list;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.home),
title: Text("ListView"),
),
body: ListView(
scrollDirection: Axis.vertical,
// reverse: true,
//vertical = 默认 false:布局从上倒下 true:从下往上
//horizontal = 默认 false:布局从左倒右 true:从右往左
// shrinkWrap: true,
padding: EdgeInsets.all(20),
children: _getList(),
),
),
);
}
}
方式2
List<Widget> _getListItem() {
return [
ListTile(
title: Text("ListTile 1"),
),
ListTile(
title: Text("ListTile 2"),
),
ListTile(
title: Text("ListTile 3"),
),
ListTile(
title: Text("ListTile 4"),
),
];
}
直接把方式1的 children: _getList(),换成 children: _getListItem(), 即可
方式3
通过构造方法里面初始化数据
import 'package:flutter/material.dart';
class ListViewPage3 extends StatelessWidget {
List<String> list = new List();
ListViewPage3() : super() {
for (var i = 0; i < 10; i++) {
list.add("ListItem = $i");
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.home),
title: Text("ListView"),
),
body: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
return ListTile(
title: Text("${list[i]}"),
leading: Icon(Icons.library_music),
subtitle: Text("副标题 ${list[i]}"),
);
})),
);
}
}
ListView实现下拉刷新(RefreshIndicator)
准备:
- StatelessWidget 要改成继承 StatefulWidget
- 准备一个正常的列表
- 使用RefreshIndicator
效果图:
刷新界面可重复看预览效果!
void main() => runApp(MyApp());
//StatelessWidget 要改成继承 StatefulWidget
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return RefreshListViewPage();
}
import 'package:flutter/material.dart';
class RefreshListViewPage extends State {
List<String> list = new List();
RefreshListViewPage() : super() {
for (var i = 0; i < 30; i++) {
list.add("ListItem = $i");
print("$i");
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.home),
title: Text("ListView"),
),
//RefreshIndicator 使用
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
return ListTile(
title: Text("${list[i]}"),
leading: Icon(Icons.library_music),
subtitle: Text("副标题 ${list[i]}"),
);
},
),
),
),
);
}
// 模拟下拉刷新的网络请求
Future<Null> _onRefresh() async {
await Future.delayed(Duration(seconds: 2), () {
setState(() {
List<String> refreshList = new List();
for (var i = 0; i < 4; i++) {
refreshList.add("下拉刷新 = $i");
}
refreshList.addAll(list);
list.clear();
list.addAll(refreshList);
});
});
}
}
ListView实现上拉加载
ListView.builder中有一个属性 controller 可借助这个属性实现Listview的滑动监听
效果图:
刷新界面可重复看预览效果!
需要复写两个方法
// 状态初始化完成
void initState() {
// TODO: implement initState
super.initState();
}
// 释放资源
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
- 在ListView.builder中使用controller属性,初始化ScrollController
ScrollController _toSontroller = ScrollController();
- 重写initState、 dispose两个方法
- 添加滑动监听
ScrollController _toSontroller = ScrollController();
//状态被初始化完成
@override
void initState() {
// TODO: implement initState
super.initState();
// 上拉加载 step 3
_toSontroller.addListener(() {
if (_toSontroller.position.pixels ==
_toSontroller.position.maxScrollExtent) {
print("列表到底啦");
// 列表滑动到底时,执行上拉加载数据
// 上拉加载 step 5
_onLoadMore();
}
});
}
- 对 itemCount、itemBuilder的属性返回进行修改
//上拉加载 step 4
itemCount: list.length + 1, // 因为增加了一个上啦加载的Widget,所以这里增加1
itemBuilder: _loadWidget, // 返回的Widget,要区分时正常数据的item的Widget,还是上拉加载的Widget
/**
* 区分上拉时返回的Widget
* */
Widget _loadWidget(BuildContext ctx, int i) {
if (i < list.length) {
// 返回正常Item的Widget
return ListTile(
title: Text("${list[i]}"),
leading: Icon(Icons.library_music),
subtitle: Text("副标题 ${list[i]}"),
);
} else {
// 返回上拉加载布局的Widget
return Center(
child: Container(
alignment: Alignment.center,
color: Colors.red,
width: double.infinity,
height: 80,
child: Text("正在加载更多..."),
),
);
}
}
- 提供上拉加载数据
/**
*上拉加载
* */
Future<Null> _onLoadMore() async {
await Future.delayed(Duration(seconds: 2), () {
setState(() {
List<String> refreshList = new List();
for (var i = 0; i < 6; i++) {
refreshList.add("上拉加载 = $i");
}
list.addAll(refreshList);
});
});
}
这5步就实现上拉加载的效果了,具体细节可以再完善,例如真实项目中加载中正在请求数据,在上拉不应该再次请求等等、、
上拉加载、下拉刷新完整代码
import 'package:flutter/material.dart';
class RefreshListViewPage extends State {
List<String> list = new List();
RefreshListViewPage() : super() {
for (var i = 0; i < 30; i++) {
list.add("ListItem = $i");
print("$i");
}
}
//上拉加载 step 1
ScrollController _toSontroller = ScrollController();
//上拉加载 step 2
//状态被初始化完成
@override
void initState() {
// TODO: implement initState
super.initState();
// 上拉加载 step 3
_toSontroller.addListener(() {
if (_toSontroller.position.pixels ==
_toSontroller.position.maxScrollExtent) {
print("列表到底啦");
// 上拉加载 step 5
_onLoadMore();
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_toSontroller.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: Icon(Icons.home),
title: Text("ListView"),
),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
//上拉加载 step 4
itemCount: list.length + 1,
itemBuilder: _loadWidget,
// 上拉加载 step 1
controller: _toSontroller,
),
),
),
);
}
Future<Null> _onRefresh() async {
await Future.delayed(Duration(seconds: 2), () {
setState(() {
List<String> refreshList = new List();
for (var i = 0; i < 4; i++) {
refreshList.add("下拉刷新 = $i");
}
refreshList.addAll(list);
list.clear();
list.addAll(refreshList);
});
});
}
/**
*上拉加载
* */
Future<Null> _onLoadMore() async {
await Future.delayed(Duration(seconds: 2), () {
setState(() {
List<String> refreshList = new List();
for (var i = 0; i < 6; i++) {
refreshList.add("上拉加载 = $i");
}
list.addAll(refreshList);
});
});
}
/**
* 区分上拉时返回的Widget
* */
Widget _loadWidget(BuildContext ctx, int i) {
if (i < list.length) {
// 返回正常Item的Widget
return ListTile(
title: Text("${list[i]}"),
leading: Icon(Icons.library_music),
subtitle: Text("副标题 ${list[i]}"),
);
} else {
// 返回上拉加载布局的Widget
return Center(
child: Container(
alignment: Alignment.center,
color: Colors.red,
width: double.infinity,
height: 80,
child: Text("正在加载更多..."),
),
);
}
}
}
完成效果图