【问题标题】:Flutter bottomNavigator with indexed stack带有索引堆栈的 Flutter bottomNavigator
【发布时间】:2020-09-30 11:40:27
【问题描述】:

关于使用索引堆栈在选项卡之间导航以显示相关页面的问题。我这样做是为了保持页面的滚动/状态。这工作正常。我可以通过单击选项卡更改当前显示的页面 - 还可以在每个页面内导航(每个页面都用它自己的导航器包装)。这是渲染页面的代码。

Widget build(BuildContext context) {
return IndexedStack(
    index: widget.selectedIndex,
    children: List.generate(widget._size, (index) {
  return _buildNavigator(index);
}));

}

Mu 问题是 IndexedStack 一次构建所有页面。在我的一些页面中,我想从 API 加载数据,我想在第一次构建小部件时并且仅当页面当前可见时才这样做。 有没有办法做到这一点?在我当前的实现中,所有小部件都会一次构建,因此即使是当前未绘制的页面也会调用我的所有 API 调用。

不确定我是否在这里遗漏了什么,或者有更好的方法来实现底部导航栏。顺便说一句,我也在使用 Provider 进行状态管理。

【问题讨论】:

    标签: flutter flutter-bottomnavigation


    【解决方案1】:

    @tsahnar 是的,我也面临与 api 调用索引小部件渲染所有小部件同时提供给其子级的相同问题,所以当各个页面独立地从 api 获取数据时,问题就来了

    试试这个:

    • 创建通过导航栏导航的小部件列表(每个小部件都带有关键构造函数,其中为每个小部件定义 PageStorageKey(<key>)
    var widgetList = <Widget>[
    Page01(key:PageStorageKey(<key>)),
    Page02(key:PageStorageKey(<key>))
    ];
    
    • 然后创建PageStorageBucket(),它会存储您的小部件状态,并在未来我们在应用程序的生命周期中需要它时提供它,即使小部件从树中被丢弃

    final _bucket = PageStorageBucket();

    • 那么 var currentIndex = 0;

    • 然后在底部导航栏存在于正文中的主页面中,而不是 IndexedStack 使用 body:PageStorage(bucket: _bucket,child:widgetsList[currentIndex])

    并在该主基本页面中创建底部导航栏,然后在导航栏图标选项卡上通过setState((){}) 将当前状态管理为currentIndex 的当前状态

    它应该可以解决您的问题,但一年后为时已晚

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题。我的解决方案是保存已加载选项卡的列表,然后使用它在Widget build(BuildContext context) 方法中构建IndexedStack 子项列表。然后在BottomNavigationBaronTap 方法中,我调用setState() 来更新加载的选项卡列表以及当前索引变量。见下文:

      class Index extends StatefulWidget {
        const Index({Key? key}) : super(key: key);
      
        @override
        _IndexState createState() => _IndexState();
      }
      
      class _IndexState extends State<Index> {
        int _currentIndex = 0;
        List loadedPages = [0,];
      
        @override
        Widget build(BuildContext context) {
          var screens = [
            const FirstTab(),
            loadedPages.contains(1) ? const SecondTab() : Container(),
            loadedPages.contains(2) ? const ThirdTab() : Container(),
            loadedPages.contains(3) ? const FourthTab() : Container(),
          ];
          return Scaffold(
            appBar: AppBar(
              // AppBar
            ),
            body: IndexedStack(
              index: _currentIndex,
              children: screens,
            ),
            bottomNavigationBar: BottomNavigationBar(
              currentIndex: _currentIndex,
              onTap: (index) {
                var pages = loadedPages;
                if (!pages.contains(index)) {
                  pages.add(index);
                }
                setState(() {
                  _currentIndex = index;
                  loadedPages = pages;
                });
              },
              items: const [
                // items
              ],
            ),
          );
        }
      }
      

      现在,第二个、第三个和第四个选项卡上的 API 调用在导航到之前不会调用。

      【讨论】:

        【解决方案3】:

        你找到解决办法了吗?
        我发现了和你一样的问题,我尝试了这个解决方法(我还没有发现任何问题)
        这个想法是制作一个新的小部件来控制进行 api 调用的小部件的可见性状态,并在它变得可见时构建它。
        在你的IndexedStack 中,用这样的小部件包装你的_buildNavigator

        class BaseTabPage extends StatefulWidget {
        
          final bool isVisible;
          final Widget child;
        
          BaseTabPage({Key key, this.child, this.isVisible});
        
          @override
          State<StatefulWidget> createState() => _BaseTabPageState();
        
        }
        
        /*
          This state is to prevent tab pages creation before show them. It'll only add the
          child widget to the widget tree when isVisible is true at least one time
          i.e. if the child widget makes an api call, it'll only do when isVisible is true
          for the first time
         */
        class _BaseTabPageState extends State<BaseTabPage> {
        
          bool alreadyShowed = false;
        
          @override
          Widget build(BuildContext context) {
            alreadyShowed = widget.isVisible ? true : alreadyShowed;
        
            return alreadyShowed ? widget.child : Container();
          }
        }
        

        例如,在我的代码中,我有这样的东西来为每个选项卡构建导航器,其中_selectedIndexBottomNavigationBar 的选定位置,tabPosition 是该页面在BottomNavigationBar 中的位置

        Widget _buildTabPage(int tabPosition) {
            final visibility = _selectedIndex == tabPosition;
            return BaseTabPage(
              isVisible: visibility,
              child: _buildNavigator(tabPosition),
            );
          }
        

        有了这个,我的 api 调用逻辑完全在子小部件中,底部导航对它们一无所知。 如果您发现它有问题,请告诉我,因为我是 Flutter 的新手。

        【讨论】:

          【解决方案4】:

          Flutter 将在堆栈中构建所有小部件,因此如果您的页面在 initState 中执行 API 调用,那么它将在构建时触发。

          您可以为 API 调用设置一个单独的函数。然后从导航器或状态管理中调用该函数。

          我希望这可以帮助您了解如何实现它。

          【讨论】:

          • 谢谢,但不确定我是否遵循。我有一个单独的 api 调用函数,但我什么时候触发调用?当构建堆栈的主屏幕构建时,堆栈中的小部件全部构建在一起。只有当用户单击选项卡并且页面显示在屏幕上时,我才需要拨打电话
          猜你喜欢
          • 1970-01-01
          • 2023-02-14
          • 2013-06-10
          • 1970-01-01
          • 1970-01-01
          • 2022-12-17
          • 2021-11-20
          • 2021-09-16
          • 1970-01-01
          相关资源
          最近更新 更多