【发布时间】:2021-04-25 13:44:00
【问题描述】:
我有一个包含 2 个页面的 PageView,每个页面都有一个自定义的导航器堆栈。
在最初开始时(假设我在第 1 页上加注星标),当我开始滚动或跳转到第 2 页时(正常)。
想到当我在第 2 页并返回第 1 页时,反之亦然,这些页面保持活动状态,我想处置/杀死它们以强制重建..至少在第 2 页上。
我试过wantKeepAlive = false,但没有用。
有人可以分享实现这一目标的方法吗?
【问题讨论】:
我有一个包含 2 个页面的 PageView,每个页面都有一个自定义的导航器堆栈。
在最初开始时(假设我在第 1 页上加注星标),当我开始滚动或跳转到第 2 页时(正常)。
想到当我在第 2 页并返回第 1 页时,反之亦然,这些页面保持活动状态,我想处置/杀死它们以强制重建..至少在第 2 页上。
我试过wantKeepAlive = false,但没有用。
有人可以分享实现这一目标的方法吗?
【问题讨论】:
如果目标是告诉我们的小部件在页面前后滑动时重建,我们可以使用PageView.builder 的onPageChanged 回调。1
onPageChanged: 将在每次查看页面时运行我们提供的函数。
onPageChanged 链接到重建页面onPageChanged 和 PageView 中的页面重建之间没有内置连接。
onPageChanged 只是运行 any 我们给它的任意函数,仅此而已。
如果我们希望使用onPageChanged 重建页面,我们需要自己创建该链接。
ValueNotifier/ValueListenableBuilder
在此示例中,我们使用ValueNotifier(buildCount 变量)通知ValueListenableBuilder 在buildCount 更改时进行重建。 (有关信息,请参阅Flutter Docs。)
每次我们滑动页面时,buildCount 会增加,页面中的ValueListenableBuilder 会重建,显示新的总数:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class PageViewRebuildPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PageView Stream Rebuild'),
),
body: PageViewRebuildExample()
);
}
}
class PageViewRebuildExample extends StatelessWidget {
final List<String> contents = ['One', 'Two', 'Three'];
final ValueNotifier<int> buildCount = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
print('Example built');
return Center(
child: PageView.builder(
itemCount: contents.length,
onPageChanged: (page) {
print('PageChanged $page');
buildCount.value++;
},
itemBuilder: (context, index) {
return Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 40, horizontal: 20),
color: Colors.lightBlueAccent,
child: ValueListenableBuilder(
valueListenable: buildCount,
// bldCnt here ↓↓ is buildCount.value
builder: (context, bldCnt, child) =>
// ↓ YOUR STUFF GOES HERE ↓
Text('Page ${contents[index]} : $bldCnt',
style: TextStyle(fontSize: 30)),
),
);
},
),
);
}
}
为了根据您的目的调整此示例,您需要将ValueListenableBuilder 的builder: 部分替换为您的小部件。每次滑动都会重建它。
如果您想知道滑动手势期间页面的精确位置,我们可以提供 PageController 到 PageView,将侦听器附加到该控制器,然后侦听 controller.page 输出:
class PageViewRebuildExample extends StatefulWidget {
@override
_PageViewRebuildExampleState createState() => _PageViewRebuildExampleState();
}
// Switched to StatefulWidget so we can add listener & dispose
class _PageViewRebuildExampleState extends State<PageViewRebuildExample> {
final List<String> contents = ['One', 'Two', 'Three'];
final ValueNotifier<int> buildCount = ValueNotifier<int>(0);
final PageController controller = PageController(); // ← our new controller
@override
void initState() {
super.initState();
controller.addListener(() { // ← add a listener in onInit
print('Precise page position ${controller.page}');
});
}
@override
void dispose() {
controller.dispose(); // don't forget to dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
print('Example built');
return Center(
child: PageView.builder(
itemCount: contents.length,
controller: controller, // ← PageController provided here
onPageChanged: (page) {
print('PageChanged $page');
buildCount.value++;
},
上面示例监听器的输出是(剪短):
I/flutter (14528): Precise page position 0.001861572265625
I/flutter (14528): Precise page position 0.006500244140625
I/flutter (14528): Precise page position 0.01019287109375
I/flutter (14528): Precise page position 0.012054443359375
... <snip>
I/flutter (14528): Precise page position 0.45981356897799835
I/flutter (14528): Precise page position 0.5179874247450384
I/flutter (14528): PageChanged 1
I/flutter (14528): Precise page position 0.5743095749455654
I/flutter (14528): Precise page position 0.6269737660740682
... <snip>
I/flutter (14528): Precise page position 0.9986377335325707
I/flutter (14528): Precise page position 0.9988375372072605
I/flutter (14528): Precise page position 0.9990080727700607
I/flutter (14528): Precise page position 1.0
1 可能还有很多其他方法可以做到这一点,这只是一种方法。例如,使用Stream 将来自onPageChanged 的事件发送到itemBuilder 内的StreamBuilder 是另一种方法。
【讨论】:
onPageChanged,以便在滚动开始时触发。
.builder() 方法中用于关闭在视口中不可见的小部件的逻辑吗?不过这个想法似乎更合适
PageController 及其page 属性。我会将其添加为答案的附录。
PageView 上的处置逻辑。为此,您必须浏览 PageView 的 SDK 定义。