Flutter 滚动控件
SingleChildScrollView
滚动组件,类似于Android中的ScrollView,只能接收一个子元素。
scrollDirection:滚动方向。
padding:设置内边距。
BouncingScrollPhysics:滚动到边界效果
- ClampingScrollPhysics:类似安卓效果,会有微光显示。
- BouncingScrollPhysics:类似ios效果,会有回弹。
- NeverScrollableScrollPhysics:禁止滚动。
- AlwaysScrollableScrollPhysics:可以滚动。
Scrollbar(
child: Container(
width: double.infinity,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(10),
child: Column(
children:
str.split("").map((e) => Text(e, textScaleFactor: 2)).toList(),
),
),
),
)
NotificationListener
可以监听ListView、NestedScrollView、GridView的滚动监听。
NotificationListener与ScrollController对比
- NotificationListener可以在任意位置监听,并且携带的信息更多。
- ScrollController只能和具体的滚动组件关联后才能监听,只能获取当前滚动位置。
ScrollNotification类里包含一个metrics属性,其类型是ScrollMetrics,包含一些信息:
var extentBefore = notification.metrics.extentBefore; //已滑出ViewPort顶部的长度,已滚动距离
var extentInside = notification.metrics.extentInside; //ViewPort内部长度,表示屏幕显示的列表部分的长度
var extentAfter = notification.metrics.extentAfter; //未划入ViewPort部分的长度
var pixels = notification.metrics.pixels; //当前滚动距离
var maxScrollExtent = notification.metrics.maxScrollExtent; //最大可滚动距离
class NotificationListenerPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _NotificationListenerPageState();
}
}
class _NotificationListenerPageState extends State<NotificationListenerPage> {
String _progress = "0%";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("滚动监听")),
body: Scrollbar(
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
double progress = notification.metrics.pixels /
notification.metrics.maxScrollExtent;
setState(() => _progress = "${(progress * 100).toInt()}%");
return false;
},
child: Stack(
alignment: Alignment.center,
children: [
ListView.builder(
itemCount: 100,
itemExtent: 50,
itemBuilder: (context, index) => ListTile(
title: Text("$index"),
),
),
CircleAvatar(
radius: 30,
child: Text(_progress),
backgroundColor: Colors.transparent.withAlpha(200),
),
],
),
),
),
);
}
}
AnimatedList
class AnimatedListPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _AnimatedListPageState();
}
}
class _AnimatedListPageState extends State<AnimatedListPage> {
final _listKey = GlobalKey<AnimatedListState>();
var data = <String>[];
int counter = 5;
@override
void initState() {
super.initState();
for (int i = 0; i < counter; i++) {
data.add("${i + 1}");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("AnimatedList"),
actions: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
addItem();
},
),
],
),
body: AnimatedList(
key: _listKey,
initialItemCount: data.length,
itemBuilder: (context, index, animation) {
return buildItem(context, index);
},
),
);
}
Widget buildItem(BuildContext context, int index) {
String c = data[index];
return ListTile(
key: ValueKey(c),
title: Text(c),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
deleteItem(context, index);
},
),
);
}
void addItem() {
data.add("${++counter}");
_listKey.currentState!.insertItem(data.length - 1);
}
void deleteItem(BuildContext context, int index) {
_listKey.currentState!.removeItem(
index,
(BuildContext context, Animation<double> animation) {
var item = buildItem(context, index);
data.removeAt(index);
return item;
},
);
}
}