Flutter:在 BottomNavigationBar 中更新 currentIndex 时,PageView 的性能滞后(但如果我不更新 currentIndex,则没有滞后)

标签 flutter dart lag

我正在创建一个带有 Scaffold 的应用程序,其中包含:

  • 一个 FutureBuilder在创建 PageView 的正文中加载数据时作为其子项。
  • 一个 BottomNavigationBarPageView 同步以获得更直观的导航。

  • 功能方面,一切正常。我可以在页面和currentIndex之间左右滑动在 BottomNavigationBar 中正确更新,如果我点击 BottomNavigationBar元素 PageView将按预期动画到正确的页面。
    但是...性能是 真的在页面之间切换时很糟糕,即使在配置文件模式下也是如此。
    经过大量调查,我已确认仅存在滞后 如果我更新 currentIndexBottomNavigationBar .
    如果我不更新 BottomNavigationBar , 在页面之间切换时动画仍然非常流畅,无论是在 PageView 上滑动时当点击 BottomNavigationBar元素本身。
    我还可以确认使用 setState 时发生的情况完全相同。当使用 Provider .我真的希望它只是 setState方法效率低下......但没有运气:(
    对于setState impementation,这就是我正在做的事情:
    PageView :
    onPageChanged: (page) {
      setState(() {
        _selectedIndex = page;
      });
    }
    
    在底部栏导航上:
    onTap: _onTappedBar,
    currentIndex: _selectedIndex
    
    及以下:
    void _onTappedBar(int value) {
      _pageController.animateToPage(value, duration: Duration(milliseconds: 500), curve: Curves.ease);
      setState(() {
        _selectedIndex = value;
      });
    }
    
    如果我注释掉这两个 setState方法,应用程序再次变得光滑,我可以使用 BottomNavigationBar也正确 - 它只是不更新​​所选项目。
    有趣的是,如果我只注释掉两个 setState 中的行方法( _selectedIndex = page;_selectedIndex = value; ),但将方法留在那里,该应用程序仍然滞后即使 setState方法是完全空的,没有更新任何东西......??
    这是Provider版本:
    PageView :
    onPageChanged: (page) {
      Provider.of<BottomNavigationBarProvider>(context, listen: false).currentIndex = page;
    }
    
    BottomBarNavigation :
    onTap: _onTappedBar,
    currentIndex: Provider.of<BottomNavigationBarProvider>(context).currentIndex,
    
    及以下:
    void _onTappedBar(int value) {
      Provider.of<BottomNavigationBarProvider>(context, listen: false).currentIndex = value;
      pageController.animateToPage(value, duration: Duration(milliseconds: 500), curve: Curves.ease);
    }
    
    如前所述,与 setState 一样滞后版本 :(
    知道是什么导致了这种滞后以及如何解决这个问题吗?我真的不知道还能尝试什么。

    最佳答案

    好的,所以我想我设法解决了这个问题,同时也学到了关于 Flutter 的宝贵一课!
    我的 setState 走在了正确的轨道上/Provider困境 - 你确实需要使用 Provider (或其他状态管理解决方案)如果您想避免重建整个页面。
    然而,这还不够。
    为了利用该实现的模块化,您还需要在主小部件之外提取相关小部件(在本例中为整个 BottomNavigationBar )。如果您不这样做,主页上的所有内容似乎仍将被重建,即使只有一个小部件正在监听 Provider。通知。
    所以这是我的root_screen的结构的build现在方法(简化正文内容以提高可读性):

    Widget build(BuildContext context) {
      return Scaffold(
        body: PageView(
          controller: _pageController,
            children: <Widget>[
              HomeScreen(),
              PerformanceScreen(),
              SettingsScreen(),
            ],
          onPageChanged: (page) {
            Provider.of<BottomNavigationBarProvider>(context, listen: false).currentIndex = page;
          },
        );
        bottomNavigationBar: MyBottomNavigationBar(onTapped: _onTappedBar),
      );
    }
    
    注意 bottomNavigationBar: root_screen 中不再定义参数.相反,我在一个单独的 Dart 文件中创建了一个新类(一个 StatelessWidget),它接受一个 onTapped函数作为参数,我从这里实例化它。
    _onTappedBar函数在 root_screen 上定义,就在 build 的下方方法:
    void _onTappedBar(int value) {
      Provider.of<BottomNavigationBarProvider>(context, listen: false).currentIndex = value;
      _pageController.animateToPage(value, duration: Duration(milliseconds: 500), curve: Curves.ease);
    }
    
    这是包含新 MyBottomNavigationBar 的单独 Dart 文件类(class):
    class MyBottomNavigationBar extends StatelessWidget {
      @override
      const MyBottomNavigationBar({
        Key key,
        @required this.onTapped,
      }) : super(key: key);
      final Function onTapped;
    
      Widget build(BuildContext context) {
        return BottomNavigationBar(
          items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
            BottomNavigationBarItem(
                icon: Icon(Icons.trending_up), title: Text('Performance')),
            BottomNavigationBarItem(
                icon: Icon(Icons.settings), title: Text('Settings')),
          ],
          onTap: onTapped,
          currentIndex:
              Provider.of<BottomNavigationBarProvider>(context).currentIndex,
        );
      }
    }
    
    同样为了完整性(并且因为我绝对需要知道),我尝试使用 setState再次靠近,同时保持 BottomNavigationBar在其新的单独文件中。我想了解仅提取小部件是否足以解决问题,或者无论如何您仍然需要使用状态管理解决方案。
    事实证明……这还不够!即使在其自己的类文件中提取了 BottomNavigationBar 小部件,使用 setState 的性能也很糟糕。
    所以最重要的是,为了让您的应用程序高效和动画流畅,请记住 尽可能多地提取小部件并模块化您的 Flutter 代码 ,以及使用状态管理解决方案而不是 setState .这似乎是避免不必要的重绘的唯一方法(并且您的代码显然会更干净,更容易调试)。

    关于Flutter:在 BottomNavigationBar 中更新 currentIndex 时,PageView 的性能滞后(但如果我不更新 currentIndex,则没有滞后),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63494061/

    相关文章:

    Flutter:如何获取文件类的 Assets 路径(视频)

    dart - 如何在 dart flutter 中从 statefulwidget 类获取变量到状态类?

    python - Pandas :使用分组数据创建滞后列

    javascript - 为什么多次调用 setTimeout() 会造成如此大的延迟?

    java - Android 上的 Flutter path_provider 错误,而在 iOS 上运行完美

    dart - 返回并显示小吃

    Android Studio 不显示带有 Flutter 的 Logcat

    dart - 角 Dart : Property binding ngIf not used by any directive on an embedded template error while using *ngIf

    dart - 在 Flutter 中使用 JS 库

    R 如何使用 case_when() 确定列中的前一个值是否大于有序向量中的前一个值