在Flutter中的PageView中动态创建或重新排序子窗口小部件



上下文:想象一下Snapchat UI。您在您的好友列表屏幕上(在相机屏幕的左侧(。你在朋友的名字上从左向右滑动,Snapchat会在滑动时为该朋友从朋友列表屏幕切换到聊天窗口设置动画。

所需行为:在垂直列表中的任何互动程序上从右向左滑动,显示与该互动程序相关的右侧上下文屏幕。在上下文屏幕中,从左向右滑动可返回互动程序列表屏幕。

当前方法:使用带有两个子级的PageView小部件。第一个子项是好友列表小部件。第二个子将是任何瓦片的上下文屏幕小部件;向左滑动";为了实现这一点,第二个子项需要动态创建(也就是说,在运行时(,也许可以将每个tile包装在GestureDetector小部件中,并在给定tile的onHorizontalDragStart回调函数中设置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);
}
}

最新更新