【问题标题】:Flutter: Child Widget's looses state when parent's sate changesFlutter:当父状态更改时,子小部件会丢失状态
【发布时间】:2021-06-27 10:02:59
【问题描述】:

我正在学习 Flutter 并正在努力解决一些状态管理问题。

我有一个 HomeScreen 小部件,其中包含 Scaffold 和 BottomNavigationBar。要根据 BottomNavigationBar 中的选定选项卡切换页面,我将 PageView 与 PageController 一起使用。以下是 HomeScreen 小部件的 build 方法的外观:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: _currentIndex == 2,
      appBar: AppBar(...properties),
      body: PageView(
        controller: _pageController,
        children: _pages,
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[...items],
        currentIndex: _currentIndex,
        onTap: _onItemTapped,  //This changes state _currentIndex and calls the method _pageController.jumpToPage(_currentIndex);
      ),
    );
  }
  • _currentIndex 最初为 0。
  • _pages 是一个包含 3 个小部件的列表。
  • _pageController 是简单的 PageController,initialPage 设置为 0。

如果您注意到我正在使用 extendBodyBehindAppBar: _currentIndex == 2 的属性,该属性正在使用 _currentIndex 状态,这会导致问题。 当我点击 BottomNavigationBar 上的最后一个选项卡时,_currentIndex 状态更改为 2,因此 extendBodyBehindAppBar 设置为 true,这使得整个 Scaffold 自行重建并且 PageView 的状态丢失。

如果注释掉 extendBodyBehindAppBar: _currentIndex == 2 行,那么即使 Scaffold 重建 PageView 小部件的状态也会被保留。

据我了解,即使父部件重建,Flutter 也应该保持子部件的状态,因为 WidgetTree 没有更改或重新排列。我尝试在 PageView 上使用 Key,但没有任何效果。

非常感谢任何帮助。

【问题讨论】:

    标签: flutter flutter-state


    【解决方案1】:

    参考Lucas Salton Cardinali post on medium 您需要使用PageStorage 来保持您在销毁后需要的孩子的状态。

    这里是从同一页面检索的示例:

    import 'package:flutter/material.dart';
    
    // ...
    
    void main() => runApp(MyApp());
    
    // ...
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final List<Widget> pages = <Widget>[
        ColorBoxPage(
          key: PageStorageKey('pageOne'),
        ),
        ColorBoxPage(
          key: PageStorageKey('pageTwo'),
        )
      ];
      int currentTab = 0;
      final PageStorageBucket _bucket = PageStorageBucket();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Persistence Example"),
          ),
          body: PageStorage(
            child: pages[currentTab],
            bucket: _bucket,
          ),
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: currentTab,
            onTap: (int index) {
              setState(() {
                currentTab = index;
              });
            },
            items: <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                label: 'page 1',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.settings),
                label: 'page2',
              ),
            ],
          ),
        );
      }
    }
    
    class ColorBoxPage extends StatelessWidget {
      ColorBoxPage({
        Key? key,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemExtent: 250.0,
          itemBuilder: (context, index) => Container(
            padding: EdgeInsets.all(10.0),
            child: Material(
              color: index % 2 == 0 ? Colors.cyan : Colors.deepOrange,
              child: Center(
                child: Text(index.toString()),
              ),
            ),
          ),
        );
      }
    }
    

    【讨论】:

    • 非常感谢您。我一定会试试这个。我的另一个问题是,如果父母的状态发生了变化,颤振会重新创建孩子吗?我认为如果 WidgetTree 未更改,它不会重新创建。
    猜你喜欢
    • 2022-12-12
    • 2020-04-14
    • 2021-06-29
    • 1970-01-01
    • 2018-11-13
    • 2019-06-26
    • 2021-06-08
    • 2021-07-25
    • 2019-04-26
    相关资源
    最近更新 更多