How to Persist Drawer Through App In Flutter?

· 6 min read
How to Persist Drawer Across All Pages In Flutter
How to Persist Drawer Across All Pages In Flutter

The drawer is one type of ListView Widget which is used for switch pages in the application as a user will select an option. So in this article, we will go through How to Persist Drawer Through App In Flutter?

How to Persist Drawer Through App In Flutter?

To Persist Drawer Through App follow the steps as below:

  • Create a class for your drawer

Your widget should be its own stateful or stateless widget. This way, you just have to instantiate it each time.

class MyDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(...);
  }
}

And then when using it on each page:

Scaffold(
  drawer: MyDrawer(...),
  ...
)
  • Create a class for your scaffold

If having to include the same drawer in a scaffold for each page is still too much code, you can instead use a class that encapsulates your scaffold. It would essentially take inputs for each of the scaffold inputs you actually use.

class MyScaffold extends StatelessWidget {

  final Widget body;

  MyScaffold({this.body});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
     body: body,
     drawer: MyDrawer(...),
    );
  }
}
  • To share a drawer between all pages we could add a builder in our MaterialApp instance. This will instantiate a Scaffold under Navigator but above all routes.
    MaterialApp(
      title: 'Flutter Demo',
      builder: (context, child) {
        return Scaffold(
          drawer: MyDrawer(),
          body: child,
        );
      },
      home: MyHome()
    )

    Inside your page, you can instantiate another Scaffold without restriction as you’d usually do.

You can then show the shared drawer by doing the following in any widget under MaterialApp :

final ScaffoldState scaffoldState = context.rootAncestorStateOfType(TypeMatcher<ScaffoldState>());
scaffoldState.openDrawer();
class RootScaffold {
  static openDrawer(BuildContext context) {
    final ScaffoldState scaffoldState =
        context.rootAncestorStateOfType(TypeMatcher<ScaffoldState>());
    scaffoldState.openDrawer();
  }
}
  • Navigation Drawer with Multiple Fragments using bloc package

First, add below dependencies in your pubspec.yaml file

flutter_bloc: ^4.0.0

Now create the below files.

drawer_event.dart

import 'nav_drawer_state.dart';
abstract class NavDrawerEvent {
const NavDrawerEvent();
}
class NavigateTo extends NavDrawerEvent {
final NavItem destination;
const NavigateTo(this.destination);
}

nav_drawer_bloc.dart

import 'package:bloc/bloc.dart';

import 'drawer_event.dart';
import 'nav_drawer_state.dart';

class NavDrawerBloc extends Bloc<NavDrawerEvent, NavDrawerState> {

  @override
  NavDrawerState get initialState => NavDrawerState(NavItem.homePage);

  @override
  Stream<NavDrawerState> mapEventToState(NavDrawerEvent event) async* {
    if (event is NavigateTo) {
      if (event.destination != state.selectedItem) {
        yield NavDrawerState(event.destination);
      }
    }
  }
}

nav_drawer_state.dart

class NavDrawerState {
  final NavItem selectedItem;

  const NavDrawerState(this.selectedItem);
}

enum NavItem {
  homePage,
  profilePage,
  orderPage,
  myCart,
}

Now it’s time to create an actual drawer like the below:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/drawer_event.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_state.dart';

class NavDrawerWidget extends StatelessWidget {
  final String accountName;
  final String accountEmail;
  final List<_NavigationItem> _listItems = [
    _NavigationItem(true, null, null, null),
    _NavigationItem(false, NavItem.homePage, "Home", Icons.home),
    _NavigationItem(false, NavItem.profilePage, "Profile Page", Icons.person),
    _NavigationItem(false, NavItem.orderPage, "My Orders", Icons.list),
    _NavigationItem(false, NavItem.myCart, "My Cart", Icons.shopping_cart),
  ];

  NavDrawerWidget(this.accountName, this.accountEmail);

  @override
  Widget build(BuildContext context) => Drawer(
          child: Container(
        child: ListView.builder(
            padding: EdgeInsets.zero,
            itemCount: _listItems.length,
            itemBuilder: (BuildContext context, int index) =>
                BlocBuilder<NavDrawerBloc, NavDrawerState>(
                  builder: (BuildContext context, NavDrawerState state) =>
                      _buildItem(_listItems[index], state),
                )),
      ));

  Widget _buildItem(_NavigationItem data, NavDrawerState state) =>
      data.header ? _makeHeaderItem() : _makeListItem(data, state);

  Widget _makeHeaderItem() => UserAccountsDrawerHeader(
        accountName: Text(accountName, style: TextStyle(color: Colors.white)),
        accountEmail: Text(accountEmail, style: TextStyle(color: Colors.white)),
        decoration: BoxDecoration(color: Colors.indigo),
        currentAccountPicture: CircleAvatar(
          backgroundColor: Colors.white,
          foregroundColor: Colors.amber,
          child: Icon(
            Icons.person,
            size: 54,
          ),
        ),
      );

  Widget _makeListItem(_NavigationItem data, NavDrawerState state) => Card(
        shape: ContinuousRectangleBorder(borderRadius: BorderRadius.zero),
        borderOnForeground: true,
        elevation: 0,
        margin: EdgeInsets.zero,
        child: Builder(
          builder: (BuildContext context) => ListTile(
            title: Text(
              data.title,
              style: TextStyle(
                color: data.item == state.selectedItem ? Colors.green : Colors.blueGrey,
              ),
            ),
            leading: Icon(
              data.icon,
              color: data.item == state.selectedItem ? Colors.green : Colors.blueGrey,
            ),
            onTap: () => _handleItemClick(context, data.item),
          ),
        ),
      );

  void _handleItemClick(BuildContext context, NavItem item) {
    BlocProvider.of<NavDrawerBloc>(context).add(NavigateTo(item));
    Navigator.pop(context);
  }
}

class _NavigationItem {
  final bool header;
  final NavItem item;
  final String title;
  final IconData icon;

  _NavigationItem(this.header, this.item, this.title, this.icon);
}

Main.dart will look like below:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_bloc.dart';
import 'package:flutterdrawerwithbloc/bloc/nav_drawer_state.dart';
import 'package:flutterdrawerwithbloc/drawer_widget.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Navigation Drawer Demo',
      theme: ThemeData(primarySwatch: Colors.blue, scaffoldBackgroundColor: Colors.white),
      home: MyHomePage(),
    );
    ;
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  NavDrawerBloc _bloc;
  Widget _content;

  @override
  void initState() {
    super.initState();
    _bloc = NavDrawerBloc();
    _content = _getContentForState(_bloc.state.selectedItem);
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => BlocProvider<NavDrawerBloc>(
      create: (BuildContext context) => _bloc,
      child: BlocListener<NavDrawerBloc, NavDrawerState>(
        listener: (BuildContext context, NavDrawerState state) {
          setState(() {
            _content = _getContentForState(state.selectedItem);
          });
        },
        child: BlocBuilder<NavDrawerBloc, NavDrawerState>(
          builder: (BuildContext context, NavDrawerState state) => Scaffold(
            drawer: NavDrawerWidget("AskNilesh", "[email protected]"),
            appBar: AppBar(
              title: Text(_getAppbarTitle(state.selectedItem)),
              centerTitle: false,
              brightness: Brightness.light,
              backgroundColor: Colors.indigo,
            ),
            body: AnimatedSwitcher(
              switchInCurve: Curves.easeInExpo,
              switchOutCurve: Curves.easeOutExpo,

Conclusion:

In this article, we have learned about How to Persist Drawer Through App In Flutter?

Thanks for Reading!!!
Keep Learning.

Do let us know if you need any assistance with Flutter Development?

FlutterAgency.com is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget GuideFlutter ProjectsCode libs and etc.

FlutterAgency.com is one of the most popular online portal dedicated to Flutter Technology and daily thousands of unique visitors come to this portal to enhance their knowledge on Flutter.

Leave a Reply