Флаттер: сохранение состояния при смене тела в выдвижном ящике - PullRequest
0 голосов
/ 09 мая 2019

Я создаю приложение Flutter с блоком навигации, используя класс Drawer библиотеки материалов.Widget, содержащий Drawer, представляет собой StatefulWidget, а содержимое Scaffold отображается в соответствии с выбранным элементом на панели навигации.Контент имеет значение WidgetOne или WidgetTwo, оба поддерживают свое собственное состояние как StatefulWidget s.См. Пример кода ниже.

В тот момент, когда я переключаюсь с одного виджета на другой и обратно, все состояние ранее отображенного виджета перезагружается.Это не идеально, так как оба виджета имеют сетевые вызовы от API, и их необходимо соответствующим образом перерисовать.

То, что я пробовал до сих пор

  • Реализация AutomaticKeepAliveClientMixin на обоихвспомогательные виджеты, как предлагается здесь: https://stackoverflow.com/a/50074067/4009506. Однако, это не похоже на работу.
  • Использование IndexedStack, как предлагается здесь: https://stackoverflow.com/a/54999503/4009506. Это загружает все виджеты напрямую, дажеесли они еще не отображаются.

Код

class DrawerWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _DrawerState();
}

class _DrawerState extends State<DrawerWidget> {
  Widget _activeWidget;

  @override
  void initState() {
    _activeWidget = FirstWidget();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("Drawer demo")),
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              ListTile(
                title: Text("First Widget"),
                onTap: () {
                  setState(() {
                    _activeWidget = FirstWidget();
                  });
                },
              ),
              ListTile(
                title: Text("Second Widget"),
                onTap: () {
                  setState(() {
                    _activeWidget = SecondWidget();
                  });
                },
              ),
            ],
          ),
        ),
        body: _activeWidget);
  }
}

class FirstWidget extends StatefulWidget {
  // [..]
}

class SecondWidget extends StatefulWidget {
  // [..]
}

Желаемый результат

WidgetOne и WidgetTwo загружаются только при начальной загрузке (после выбораих в Drawer).Переключение на другой виджет и обратно не должно перезагружать виджет, если он уже был загружен ранее.Подвиджеты не должны загружать все напрямую, только при их первоначальном нажатии.

Фактический результат

Оба FirstWidget и SecondWidget перезагружаются и перерисовываются каждый раз, когда выбираются в Drawer.

1 Ответ

0 голосов
/ 22 мая 2019

Я решил эту проблему, используя PageView и внедрив AutomaticKeepAliveClientMixin во все вспомогательные виджеты:

class DrawerWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _DrawerState();
}

class _DrawerState extends State<DrawerWidget> {
  final _pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("Drawer demo")),
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              ListTile(
                title: Text("First Widget"),
                onTap: () {
                  _pageController.jumpToPage(0);
                },
              ),
              ListTile(
                title: Text("Second Widget"),
                onTap: () {
                  _pageController.jumpToPage(1);
                },
              ),
            ],
          ),
        ),
        body: PageView(
          controller: _pageController,
          children: <Widget>[
            FirstWidget(),
            SecondWidget()
          ],
          physics: NeverScrollableScrollPhysics()
        ));
  }
}

class FirstWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _FirstWidgetState();
}

class _FirstWidgetState extends State<FirstWidget> with AutomaticKeepAliveClientMixin<FirstWidget> {
  // [..]

  @override
  bool get wantKeepAlive => true;
} 

class SecondWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _SecondWidgetState();
}

class _SecondWidgetState extends State<SecondWidget> with AutomaticKeepAliveClientMixin<SecondWidget> {
  // [..]

  @override
  bool get wantKeepAlive => true;
}

Теперь все виджеты загружаются только после первоначального переключения в навигационном блоке и не перезагружаются при переключении обратно.

...