滚动列表与动态加载
ListView
//特点:一次性加载完所有东西,对于列项多的项目非常耗性能
ListView(
children: [
Container(
height: 300,
width: 300,
color: Colors.red,
),
Text('nihao flutter'),
Text('Hello world'),
Container(
height: 300,
width: 300,
color: Colors.red,
),
Text('Hello world'),
Container(
height: 300,
width: 300,
color: Colors.red,
),
Text('Hello world'),
Container(
height: 300,
width: 300,
color: Colors.red,
),
Text('Hello world'),
Container(
height: 300,
width: 300,
color: Colors.red,
),
],
),
ListView.builder
ListView.builder(
itemCount: 100, //条目
itemExtent: 100, //每一条条目的高度
cacheExtent: 300, //缓冲区域(预加载)
itemBuilder: (context, index) {
return Container(
height: 100,
width: double.infinity,
color: Colors.blue[200],
alignment: Alignment.center,
child: Text('$index'));
},
),
ListView.separated
ListView.separated(
separatorBuilder: (context, index) {
return Divider(//分割线
height: 1,
);
},
itemCount: 100, //条目
cacheExtent: 300, //缓冲区域(预加载),
itemBuilder: (context, index) {
return Container(
height: 100,
width: double.infinity,
color: Colors.blue[200],
alignment: Alignment.center,
child: Text('$index'));
},
)
深入详解ListView组件
//定义controller
//final _controller = ScrollController();
Scrollbar(
child: ListView.builder(
//physics: NeverScrollableScrollPhysics(),//不能滚动了
controller: _controller,//设置控制器
padding: const EdgeInsets.only(bottom: 140),//底部留有空白
//scrollDirection: Axis.horizontal,//横竖屏切换
itemExtent: 60,
itemCount: 80,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.person),
title: Text('Name'),
subtitle: Text('Introduction'),
trailing: IconButton(
icon: Icon(Icons.delete_outline),
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
//按一次下降200像素
_controller.animateTo(_controller.offset + 200,
duration: Duration(seconds: 2),
curve: Curves.linear);
},
child: Icon(Icons.arrow_circle_down_outlined),
),
),
点击标题回到top
AppBar(
centerTitle: true,
title: GestureDetector(
onTap: () {
_controller.animateTo(
-20.0,
duration: Duration(seconds: 1),
curve: Curves.linear);
},
child: Text(
'滚动列表',
)),
),
下拉刷新与通知事件
RefreshIndicator(
strokeWidth: 2.0, //指示器宽度
color: Colors.white, //指示器颜色
backgroundColor: Colors.black, //背景颜色
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
child: Scrollbar(
child: ListView.builder(
//physics: NeverScrollableScrollPhysics(),//不能滚动了
controller: _controller,
padding: const EdgeInsets.only(bottom: 140),
//scrollDirection: Axis.horizontal,
itemExtent: 60,
itemCount: 80,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.person),
title: Text('Name'),
subtitle: Text('Introduction'),
trailing: IconButton(
icon: Icon(Icons.delete_outline),
),
);
},
),
),
),
NotificationListener(
//拦截监听
onNotification: (ScrollNotification _event) {
print(_event);
return false; //是否拦截向上冒泡事件,true:上层监听不到事件
},
child: ListView.builder(
//physics: NeverScrollableScrollPhysics(),//不能滚动了
controller: _controller,
padding: const EdgeInsets.only(bottom: 140),
//scrollDirection: Axis.horizontal,
itemExtent: 60,
itemCount: 80,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.person),
title: Text('Name'),
subtitle: Text('Introduction'),
trailing: IconButton(
icon: Icon(Icons.delete_outline),
),
);
},
),
),
支持滑动删除的Dismissible
Dismissible(
confirmDismiss: (direction) async {
await Future.delayed(Duration(seconds: 2));
return true; //是否删除
},
onResize: () {
//即将消失时不断调用
print('on resizing');
},
dismissThresholds: {
//滑动后自动滑动的百分比
DismissDirection.startToEnd: 0.4,
DismissDirection.endToStart: 0.4
},
resizeDuration: Duration(seconds: 5), //消失的时间
movementDuration: Duration(seconds: 5), //指示器滑动时间
background: Container(color: Colors.red), //从左到右滑动颜色
secondaryBackground: Container(color: Colors.black), //从右到左滑动颜色
onDismissed: (direction) {
//监听
print(direction);
},
key: UniqueKey(),
child: Container(
height: 50,
color: Colors.blue[index % 9 * 100],
),
);
实例:GitHub最新动态
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
final _events = [];
_refresh() async {
final res = await http.get("https://api.github.com/events");
if (res.statusCode == 200) {
final List json = convert.jsonDecode(res.body);
// print(json); //Map代表json类型
setState(() {
_events.clear();
_events.addAll(json.map((element) => GitEvent(element)));
});
}
}
@override
Widget build(BuildContext context) {
return Scrollbar(
child: RefreshIndicator(
onRefresh: () async {
await _refresh();
},
child: ListView(
children: _events.map((event) {
return Dismissible(
confirmDismiss: (_) async {
return showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text('Are you sure?'),
content: Text('Do you want to delete this item?'),
actions: [
FlatButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text('Cancel')),
FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text('Delete'))
],
);
},
);
},
onDismissed: (_) {
setState(() {
_events.removeWhere((e) => e.id == event.id);
});
},
key: ValueKey(event.id),
child: ListTile(
leading: Image.network(
'http://www.tobutomi.top/NewsCat/images/avatar/avatar.jpg'),
title: Text('${event.userName}'),
subtitle: Text('${event.repoName}'),
),
);
}).toList(),
),
),
);
}
}
class GitEvent {
String id;
String userName;
String avatarUrl;
String repoName;
GitEvent(json) {
this.id = json['id'];
this.userName = json['actor']['login'];
this.avatarUrl = json['actor']['avatar_url'];
this.repoName = json['repo']['name'];
}
@override
String toString() {
// TODO: implement toString
return 'GitEvent{id:$id,userName:$userName,avatarUrl:$avatarUrl,repoName:$repoName}';
}
}
GridView(二维网格列表)详解
GridView.builder(
//固定个数
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, //每一行的网格个数
childAspectRatio: 16 / 9, //修改网格比例
mainAxisSpacing: 2.0, //上下间隙
crossAxisSpacing: 4.0, //左右间隙
),
//固定最大宽度
// gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
// childAspectRatio: 16 / 9,
// maxCrossAxisExtent: 120,//每一行的个数通过最大宽度来变化
// ),
itemCount: 80,
itemBuilder: (context, index) {
return Center(
child: Container(
width: double.infinity,
height: 100,
color: Colors.blue[index % 8 * 100],
child: Text('$index'),
),
);
});
ListWheelScrollView(
physics: FixedExtentScrollPhysics(), //停留在中间
onSelectedItemChanged: (index) => print("selected $index"), //项目选择
magnification: 2.5, //中间放大
useMagnifier: true, //是否使用放大镜
// overAndUnderCenterOpacity: 0.2, //除了中间,其他的透明度
// offAxisFraction: -1.5, //轴心的偏移
diameterRatio: 2.0, //直径比例
itemExtent: 100,
children: List.generate(
20,
(index) => Container(
color: Colors.blue,
child: Text('Hello'),
alignment: Alignment.center,
)),
);
拓展,横向
RotatedBox(
quarterTurns: 1,
child: ListWheelScrollView(
physics: FixedExtentScrollPhysics(), //停留在中间
onSelectedItemChanged: (index) => print("selected $index"), //项目选择
magnification: 2.5, //中间放大
useMagnifier: true, //是否使用放大镜
// overAndUnderCenterOpacity: 0.2, //除了中间,其他的透明度
// offAxisFraction: -1.5, //轴心的偏移
diameterRatio: 2.0, //直径比例
itemExtent: 100,
children: List.generate(
20,
(index) => RotatedBox(
quarterTurns: -1,
child: Container(
//color: Colors.blue,
child: Text(
'$index',
style: TextStyle(fontSize: 48),
),
alignment: Alignment.center,
),
)),
),
);
PageView
PageView(
pageSnapping: true, //可以不停在一个页面上
scrollDirection: Axis.vertical, //竖直方向
children: [
Container(color: Colors.blue),
Container(color: Colors.orange)
],
onPageChanged: (value) => print('selected:$value'), //监听
);
ReorderableListView
ReorderableListView(
children: List.generate(
20, (index) => Text('index is $index', key: UniqueKey())),
onReorder: (int oldIndex, int newIndex) =>
print('moved from $oldIndex to $newIndex'));
//包裹上后,布局溢出的时候可以滚动
SingleChildScrollView(
child: Column(
children: [
FlutterLogo(size: 300),
FlutterLogo(size: 400),
],
),
);