MohammadBaqer
MohammadBaqer

Reputation: 1415

one Drawer for all screens in flutter web

i'm new to flutter and I want to create a web app with drawer and couple of screens. here is my main function and root of apps ui:

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

class MyApp extends StatelessWidget {
    const MyApp({super.key});

@override
Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Tapchi Admin Panel',
        theme: ThemeData.dark().copyWith(
          scaffoldBackgroundColor: bgColor,
          textTheme: GoogleFonts.poppinsTextTheme(Theme
              .of(context)
              .textTheme)
              .apply(bodyColor: Colors.white),
          canvasColor: secondaryColor,
        ),
        home: const DashboardScreen()
    );
  }
}

and here is my DashboardScreen:

class DashboardScreen extends StatelessWidget {
  const DashboardScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    );
  }
}

and here is my SideMenu:

class SideMenu extends StatelessWidget {
  const SideMenu({super.key});

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
      children: [
        const DrawerHeader(child: Icon(Icons.android)),
        SideMenuItem(
            title: 'dashboard',
            leadingIcon: Icons.dashboard,
            press: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => const DashboardScreen()));
              }),
        SideMenuItem(
            title: 'users',
            leadingIcon: Icons.person,
            press: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => const UserScreen()));
            }),
      ],
    ),
  );
 }
}

my problem is when i navigate into DashboardScreen i lose AppBar and Drawer but I want to have them for entire application!. in android we could solve this problem by using NavHost. how can I have one Drawer for my whole app. by the way i'm developing a webApp

Upvotes: 1

Views: 2498

Answers (2)

MarcoFerreira
MarcoFerreira

Reputation: 378

We had a massive web project where this was a must and quite some research was done. We found a few approaches and indeed you can create 2 navigators, however, there are already features to support this without any workaround. What we used was GoRouter which has not only normal routes (called GoRoutes) but also ShellRoutes where the nested routes. With this implementation, you will go to a different route inside the shellRoute without changing whatever parent widget code is inside the shellRoute - a drawer or anything else. If you want to change it, one approach is to have other shell route with a different top level widget (or without any - image a page with no drawer al tall). Or you could simply conditionally change the widget on the first shellRoute to show for example an empty container when you want to remove the drawer.

Here is a code sample using shellRoute for this purpose:

static GoRouter mainRouter = GoRouter(
initialLocation: "/main",
routes: [
  ShellRoute(
    navigatorKey: mainNavigatorKey,
    builder: (context, state, child) {
      return Cookies(
        child: HomeCorePage(
          child: child,
        ),
      );
    },
    routes: [
      GoRoute(
        name: "main",
        path: "/main",
        builder: (context, state) => const HomePage(),
        routes: [
          GoRoute(
            name: "postDetails",
            path: "postDetails",
            builder: (context, state) =>
                PostDetailsPage(postId: state.params['id'] ?? ""),
          ),
          GoRoute(
            name: "chat",
            path: "chat",
            builder: (context, state) => ChatPage(),
          ),
          //...........
        ],
      ),
    ],
  ),
],
);

Last notes: GoRoute is a wrapper around the Flutter Navigator 2.0 - So you will be using the last and more flexible Navigator on your project. GoRouter has adopted by flutter and is officially recommended int theFlutter Favorite program. And last, in my experience it is super intuitive and very scalable/flexible. It also seems very mature as we search and found several issues on github that were closed and were related to older versions.

Hope it helps. Cheers

Upvotes: 1

Ante Bule
Ante Bule

Reputation: 2136

Ok, I managed to do that using two MaterialApp widgets and a global navigatorKey variable. Here is an example:

import 'package:flutter/material.dart';

final navigatorKey = GlobalKey<NavigatorState>();

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Sample();
  }
}

class Sample extends StatelessWidget {
  const Sample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        drawer: SideMenu(),
        // use new MaterialApp to push new (sub)screens on top of that area and preserve the same drawer
        body: MaterialApp(
          navigatorKey: navigatorKey,
          home: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Center(child: Text('Home screen')),
      ),
    );
  }
}

class SideMenu extends Drawer {
  const SideMenu({super.key});

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: Column(
        children: [
          const DrawerHeader(child: Icon(Icons.android)),
          SideMenuItem(
              title: 'dashboard',
              leadingIcon: Icons.dashboard,
              press: () {
                Navigator.push(
                    navigatorKey.currentContext!,
                    MaterialPageRoute(
                        builder: (context) => const DashboardScreen()));
              }),
          SideMenuItem(
              title: 'users',
              leadingIcon: Icons.person,
              press: () {
                Navigator.push(
                    navigatorKey.currentContext!,
                    MaterialPageRoute(
                        builder: (context) => const UserScreen()));
              }),
        ],
      ),
    );
  }
}

class SideMenuItem extends StatelessWidget {
  final String title;
  final IconData leadingIcon;
  final Function() press;

  const SideMenuItem({
    super.key,
    required this.title,
    required this.leadingIcon,
    required this.press,
  });
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: Icon(leadingIcon),
      title: Text(title),
      onTap: press,
    );
  }
}

class DashboardScreen extends StatelessWidget {
  const DashboardScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.red,
        child: Center(child: Text('Dashboard screen')),
      ),
    );
  }
}

class UserScreen extends StatelessWidget {
  const UserScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.blue,
        child: Center(child: Text('User screen')),
      ),
    );
  }
}

Upvotes: 1

Related Questions