[英]Dynamically creating or reordering children widgets in a PageView in Flutter
背景:想象一下 Snapchat UI。 您在您的好友列表屏幕上(在相机屏幕的左侧)。 您在朋友的名字上从左到右滑动,当您滑动时,Snapchat 会动画化从朋友列表屏幕到该朋友的聊天 window 的过渡。
期望行为:在垂直列表中的任何图块上从右向左滑动,以从右侧显示与该图块相关的上下文屏幕。 在上下文屏幕中,从左向右滑动以返回磁贴列表屏幕。
当前方法:使用具有两个孩子的PageView小部件。 第一个孩子是朋友列表小部件。 第二个孩子将是任何一个“向左滑动”的图块的上下文屏幕小部件。 为此,需要动态创建第二个子项(即在运行时),可能通过将每个图块包装在GestureDetector小部件中并在给定图块的onHorizontalDragStart回调 function 中设置 PageView 的第二个子项。
我的问题:您如何在 Flutter 应用程序中动态(在运行时)创建或重新排序 PageView 小部件的子级?
PageView.builder的 flutter 文档说:
PageView.builder 默认不支持子重新排序。 如果您计划稍后更改子订单,请考虑使用 PageView 或 PageView.custom。
听起来这对于 PageView 或 PageView.custom 都是可能的,但是如何呢?
他们在PageView.custom
中有一个关于重新排序处理的非常简单的示例:
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
@override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
List<String> items = <String>['1', '2', '3', '4', '5'];
void _reverse() {
setState(() {
items = items.reversed.toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: PageView.custom(
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return KeepAlive(
data: items[index],
key: ValueKey<String>(items[index]),
);
},
childCount: items.length,
findChildIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final String data = valueKey.value;
return items.indexOf(data);
}
),
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () => _reverse(),
child: const Text('Reverse items'),
),
],
),
),
);
}
}
class KeepAlive extends StatefulWidget {
const KeepAlive({Key? key, required this.data}) : super(key: key);
final String data;
@override
State<KeepAlive> createState() => _KeepAliveState();
}
class _KeepAliveState extends State<KeepAlive> with AutomaticKeepAliveClientMixin{
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Text(widget.data);
}
}
根据我的理解,这可以简化为:
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
@override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
List<String> items = <String>['1', '2', '3', '4', '5'];
void _reverse() {
setState(() {
items = items.reversed.toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: PageView.custom(
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return KeepAlive(
data: items[index],
key: ValueKey<String>(items[index]),
);
},
childCount: items.length,
// This is default, can be omitted.
addAutomaticKeepAlives: true,
findChildIndexCallback: (Key key) {
final ValueKey<String> valueKey = key as ValueKey<String>;
final String data = valueKey.value;
return items.indexOf(data);
}
),
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () => _reverse(),
child: const Text('Reverse items'),
),
],
),
),
);
}
}
class KeepAlive extends StatelessWidget {
const KeepAlive({Key? key, required this.data}) : super(key: key);
final String data;
@override
Widget build(BuildContext context) {
super.build(context);
return Text(data);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.