Flutter:当父状态更改时,子 Widget 会丢失状态

Flutter: Child Widget's looses state when parent's sate changes

我正在学习 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);
      ),
    );
  }

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

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

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

非常感谢任何帮助。

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

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

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()),
          ),
        ),
      ),
    );
  }
}