0

I am creating a Flutter application with a navigation drawer by using the Drawer class of the Material library. The Widget containing the Drawer is a StatefulWidget and the Scaffold's content is displayed according to the selected item on the navigation drawer. The content is either WidgetOne or WidgetTwo, both maintaining their own state as StatefulWidgets. See the code example below.

At the moment, when I change from one widget to another and back, the whole state of the earlier displayed widget is reloaded. This is not ideal, since both widgets have network calls from an API, and need to be redrawn accordingly.

What I've tried so far

Code

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 {
  // [..]
}

Desired result

WidgetOne and WidgetTwo are only loaded on initial load (after selecting them in the Drawer). Switching to another widget and back should not reload the widget if it was already loaded earlier. The sub widgets should not load all directly, only when they are initially pressed.

Actual result

Both FirstWidget and SecondWidget are reloaded and redrawn each time they are selected in the Drawer.

Gaston
  • 189
  • 1
  • 4
  • 14

1 Answers1

4

I resolved this issue by using a PageView and implementing AutomaticKeepAliveClientMixin on all sub widgets:

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;
}

Now, all widgets are only loaded upon initial switch in the navigation drawer and do not get reloaded when switching back.

Gaston
  • 189
  • 1
  • 4
  • 14