【问题标题】:how to dispose/kill a page in a PageView in flutter如何在 Flutter 中处理/杀死 PageView 中的页面
【发布时间】:2021-04-25 13:44:00
【问题描述】:

我有一个包含 2 个页面的 PageView,每个页面都有一个自定义的导航器堆栈。

在最初开始时(假设我在第 1 页上加注星标),当我开始滚动或跳转到第 2 页时(正常)。

想到当我在第 2 页并返回第 1 页时,反之亦然,这些页面保持活动状态,我想处置/杀死它们以强制重建..至少在第 2 页上。

我试过wantKeepAlive = false,但没有用。

有人可以分享实现这一目标的方法吗?

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    在滑动时重建

    如果目标是告诉我们的小部件在页面前后滑动时重建,我们可以使用PageView.builderonPageChanged 回调。1

    onPageChanged: 将在每次查看页面时运行我们提供的函数。

    onPageChanged 链接到重建页面

    onPageChangedPageView 中的页面重建之间没有内置连接。

    onPageChanged 只是运行 any 我们给它的任意函数,仅此而已。

    如果我们希望使用onPageChanged 重建页面,我们需要自己创建该链接。

    链接ValueNotifier/ValueListenableBuilder

    在此示例中,我们使用ValueNotifierbuildCount 变量)通知ValueListenableBuilderbuildCount 更改时进行重建。 (有关信息,请参阅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)),
                ),
              );
            },
          ),
        );
      }
    }
    

    为了根据您的目的调整此示例,您需要将ValueListenableBuilderbuilder: 部分替换为您的小部件。每次滑动都会重建它。


    附录

    如果您想知道滑动手势期间页面的精确位置,我们可以提供 PageControllerPageView,将侦听器附加到该控制器,然后侦听 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() 方法中用于关闭在视口中不可见的小部件的逻辑吗?不过这个想法似乎更合适
    • @bihireboris 不确定我是否关注您的第一个评论问题。如果您需要对页面滑动进行细粒度控制(即滚动手势期间的精确位置),我们可以使用PageController 及其page 属性。我会将其添加为答案的附录。
    • @bihireboris 对于您的第二条评论,我并不直接熟悉PageView 上的处置逻辑。为此,您必须浏览 PageView 的 SDK 定义。
    猜你喜欢
    • 2020-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多