13

I have a simple Scaffold with a drawer and a body. I want to select an item in the drawer and have the scaffold's body navigate to a new view.

Most approaches that i found (like this) just use a stateful widget and change its state when the drawer item is tapped.

However this completely ignores the navigation stack of the app, and pressing back does not return to the previous view as expected.

On the other hand, using Navigator.of(context).push... when an item is clicked uses the navigation stack, but changes the whole screen, which is also not what i want.

I tried to create a new custom navigator for the scaffold's body, but had issues accessing the NavigatorState from the Drawer.

This seems like a common problem to me (for instance, all google apps work that way) and i am a bit confused on how to implement this correctly. Is a custom navigator the correct approach? Are there some examples available?

Simiil
  • 2,281
  • 1
  • 22
  • 32
  • Are you trying to show different content in the same page with other normal Navigation bar features? – Vinoth Kumar May 29 '18 at 09:28
  • i want to just change the scaffolds body, everything around it (especially the drawer) should stay the same. There is no other navigation currently – Simiil May 29 '18 at 09:32

2 Answers2

2

It seems that you have to create a Widget only for the drawer, and include it in the Scaffold of each screen of your app. This way you can use the Navigator preserving the navigation stack, and include the drawer only in the screens you decide.

This is the article where I found an example.

Xero
  • 3,951
  • 4
  • 41
  • 73
Jesús Barrera
  • 400
  • 1
  • 5
  • 15
-1

I don't know weather this the right way to do it or not, but this is by far the best way for me to do it. Give it a try.

import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(new MaterialApp(debugShowCheckedModeBanner: false, home: new HomePage(),),);

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Widget currentPage;

  @override
  void initState() {
    super.initState();

    if(currentPage == null || _recentPages.length == 0)
      currentPage = new PageOne();
  }

  @override
  Widget build(BuildContext context) {
    return new WillPopScope( // To process back pressed event
      onWillPop: onWillPop,
      child: new Scaffold(
        appBar: new AppBar(title: new Text('Home'),),
        drawer: new Drawer(
          child: new ListView(
            children: <Widget>[
              new DrawerHeader(
                child: new UserAccountsDrawerHeader(
                  accountName: new Text('Vinoth Kumar'),
                  accountEmail: new Text('vinoth1094@gmail.com'),
                  currentAccountPicture: new CircleAvatar(
                      backgroundImage: new NetworkImage(
                          'https://scontent.fmaa1-1.fna.fbcdn.net/v/t1.0-9/16196015_10154888128487744_6901111466535510271_n.png?_nc_cat=0&oh=b987a0608ad9dad1beff57c489e53221&oe=5BB865E9')),
                ),
                padding: const EdgeInsets.all(0.0),
                margin: const EdgeInsets.all(0.0),
              ),
            ]..addAll(_buildNavigationItems()),
          ),
        ),
        body: currentPage,
      ),
    );
  }

  List<Widget> _buildNavigationItems() {
    List<Widget> navList = [];
    for (int i=0; i<_navigationItems.length; i++) {
      navList.add(new ListTile(
        title: new Text(_navigationItems[i].name),
        trailing: new Icon(_navigationItems[i].icon),
        onTap: () {
          onNavigationIconClicked(i);
        },
      ));
    }
    return navList;
  }

  onNavigationIconClicked(int i) {
    switch(_navigationItems[i].name) {
      case 'Page 1':
        if (!(currentPage is PageOne)) {
          Navigator.of(context).pop();
          setState(() {
            _recentPages.add(currentPage); // Add current page to _recentPages
            currentPage = new PageOne(); // Show new page
          });
        }
        break;
      case 'Page 2':
        if (!(currentPage is PageTwo)) {
          Navigator.of(context).pop();
          setState(() {
            _recentPages.add(currentPage); // Add current page to _recentPages
            currentPage = new PageTwo(); // Show new page
          });
        }
        break;
      case 'Page 3':
        if (!(currentPage is PageThree)) {
          Navigator.of(context).pop();
          setState(() {
            _recentPages.add(currentPage); // Add current page to _recentPages
            currentPage = new PageThree(); // Show new page
          });
        }
        break;
      case 'Page 4':
        if (!(currentPage is PageFour)) {
          Navigator.of(context).pop();
          setState(() {
            _recentPages.add(currentPage); // Add current page to _recentPages
            currentPage = new PageFour(); // Show new page
          });
        }
        break;
    }
  }

  Future<bool> onWillPop() async{
    if (_recentPages.length == 0) {
      return true;
    } else {
      setState(() {
        currentPage = _recentPages[_recentPages.length - 1];
        _recentPages.removeLast();
      });
      return false;
    }
  }
}

List<Widget> _recentPages = [];

List<NavigationItem> _navigationItems = [
  new NavigationItem('Page 1', Icons.keyboard_arrow_right),
  new NavigationItem('Page 2', Icons.keyboard_arrow_right),
  new NavigationItem('Page 3', Icons.keyboard_arrow_right),
  new NavigationItem('Page 4', Icons.keyboard_arrow_right),
];

class NavigationItem {
  final String name;
  final IconData icon;

  NavigationItem(this.name, this.icon);
}

Sample Pages:

class PageOne extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('Page One'),
    );
  }
}

class PageTwo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('Page Two'),
    );
  }
}

class PageThree extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('Page Three'),
    );
  }
}

class PageFour extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text('Page Four'),
    );
  }
}
Vinoth Kumar
  • 12,637
  • 5
  • 32
  • 38