Search code examples
flutterbloc

How to implement AppBar Drawer with bottom navigation bar in flutter bloc?


I am new to flutter bloc. I want to add side navigation drawer with bottom navigation. Can anyone help me how we can achieve this?


Solution

  • You can customize this code using the flutter bloc as well as per your requirement.

    main.dart

    import 'package:demo_app/custom_animated_bottom_bar.dart';
    import 'package:demo_app/first_screen.dart';
    import 'package:demo_app/fourth_screen.dart';
    import 'package:demo_app/home_screen.dart';
    import 'package:demo_app/messages_screen.dart';
    import 'package:demo_app/profile_screen.dart';
    import 'package:demo_app/second_screen.dart';
    import 'package:demo_app/third_screen.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key, required this.title}) : super(key: key);
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    enum ScreenType {
      firstScreen,
      secondScreen,
      thirdScreen,
      forthScreen,
      home,
      messages,
      profile
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      ScreenType _screenType = ScreenType.home;
      final _inactiveColor = Colors.grey;
    
      GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          key: _scaffoldKey,
          appBar: AppBar(
            title: Text(getTitle(_screenType)),
          ),
          drawer: Drawer(
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                DrawerHeader(
                  child: Text('Drawer Header'),
                  decoration: BoxDecoration(
                    color: Colors.blue,
                  ),
                ),
                ListTile(
                  title: Text('First Screen'),
                  onTap: () => onTabTapped(ScreenType.firstScreen),
                ),
                ListTile(
                  title: Text('Second Screen'),
                  onTap: () => onTabTapped(ScreenType.secondScreen),
                ),
                ListTile(
                  title: Text('Third Screen'),
                  onTap: () => onTabTapped(ScreenType.thirdScreen),
                ),
              ],
            ),
          ),
          body: _body(_screenType),
          bottomNavigationBar: _buildBottomBar(),
        );
      }
    
      Widget _body(ScreenType screenType) {
        switch (screenType) {
          case ScreenType.firstScreen:
            return FirstScreen(
              voidCallback: () => onTabTapped(ScreenType.forthScreen),
            );
          case ScreenType.secondScreen:
            return const SecondScreen();
          case ScreenType.thirdScreen:
            return const ThirdScreen();
          case ScreenType.forthScreen:
            return const ForthScreen();
          case ScreenType.home:
            return const HomeScreen();
          case ScreenType.messages:
            return const MessagesScreen();
          case ScreenType.profile:
            return const ProfileScreen();
        }
      }
    
      Widget _buildBottomBar() {
        return CustomAnimatedBottomBar(
          backgroundColor: Colors.black,
          selectedIndex: _screenType,
          showElevation: true,
          itemCornerRadius: 24,
          curve: Curves.easeIn,
          onItemSelected: onTabTapped,
          items: <BottomNavyBarItem>[
            BottomNavyBarItem(
              screenType: ScreenType.home,
              icon: Icon(Icons.apps),
              title: Text('Home'),
              activeColor: Colors.green,
              inactiveColor: _inactiveColor,
              textAlign: TextAlign.center,
            ),
            BottomNavyBarItem(
              screenType: ScreenType.messages,
              icon: Icon(Icons.message),
              title: Text('Messages'),
              activeColor: Colors.purpleAccent,
              inactiveColor: _inactiveColor,
              textAlign: TextAlign.center,
            ),
            BottomNavyBarItem(
              screenType: ScreenType.profile,
              icon: Icon(Icons.account_circle_rounded),
              title: Text('Profile'),
              activeColor: Colors.pink,
              inactiveColor: _inactiveColor,
              textAlign: TextAlign.center,
            ),
          ],
        );
      }
    
      void onTabTapped(ScreenType screenType) {
        if ((_scaffoldKey.currentState ?? ScaffoldState()).isDrawerOpen) {
          (_scaffoldKey.currentState ?? ScaffoldState()).openEndDrawer();
        }
        setState(() {
          _screenType = screenType;
        });
      }
    
      String getTitle(ScreenType screenType) {
        switch (screenType) {
          case ScreenType.firstScreen:
            return "First Screen";
          case ScreenType.secondScreen:
            return "Second Screen";
          case ScreenType.thirdScreen:
            return "Third Screen";
          case ScreenType.forthScreen:
            return "Forth Screen";
          case ScreenType.home:
            return "Home";
          case ScreenType.messages:
            return "Messages";
          case ScreenType.profile:
            return "Profile";
        }
      }
    }
    

    custom_animated_bottom_bar.dart

    import 'package:demo_app/main.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/widgets.dart';
    
    class CustomAnimatedBottomBar extends StatelessWidget {
      CustomAnimatedBottomBar({
        Key? key,
        this.selectedIndex = ScreenType.home,
        this.showElevation = true,
        this.iconSize = 24,
        this.backgroundColor,
        this.itemCornerRadius = 40,
        this.animationDuration = const Duration(milliseconds: 270),
        this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
        required this.items,
        required this.onItemSelected,
        this.curve = Curves.linear,
      })  : assert(items.length >= 2 && items.length <= 5),
            super(key: key);
    
      final ScreenType selectedIndex;
      final double iconSize;
      final Color? backgroundColor;
      final bool showElevation;
      final Duration animationDuration;
      final List<BottomNavyBarItem> items;
      final ValueChanged<ScreenType> onItemSelected;
      final MainAxisAlignment mainAxisAlignment;
      final double itemCornerRadius;
      final Curve curve;
    
      @override
      Widget build(BuildContext context) {
        final bgColor = backgroundColor ?? Theme.of(context).bottomAppBarColor;
    
        return Container(
          decoration: BoxDecoration(
            color: bgColor,
            boxShadow: [
              if (showElevation)
                const BoxShadow(
                  color: Colors.black12,
                  blurRadius: 2,
                ),
            ],
          ),
          child: SafeArea(
            child: Container(
              width: double.infinity,
              height: kToolbarHeight,
              padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
              child: Row(
                mainAxisAlignment: mainAxisAlignment,
                children: items.map((item) {
                  var index = item;
                  return GestureDetector(
                    onTap: () => onItemSelected(index.screenType),
                    child: _ItemWidget(
                      item: item,
                      iconSize: iconSize,
                      isSelected: index.screenType == selectedIndex,
                      backgroundColor: bgColor,
                      itemCornerRadius: itemCornerRadius,
                      animationDuration: animationDuration,
                      curve: curve,
                    ),
                  );
                }).toList(),
              ),
            ),
          ),
        );
      }
    }
    
    class _ItemWidget extends StatelessWidget {
      final double iconSize;
      final bool isSelected;
      final BottomNavyBarItem item;
      final Color backgroundColor;
      final double itemCornerRadius;
      final Duration animationDuration;
      final Curve curve;
    
      const _ItemWidget({
        Key? key,
        required this.item,
        required this.isSelected,
        required this.backgroundColor,
        required this.animationDuration,
        required this.itemCornerRadius,
        required this.iconSize,
        this.curve = Curves.linear,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Semantics(
          container: true,
          selected: isSelected,
          child: AnimatedContainer(
            width: isSelected ? 130 : 50,
            height: double.maxFinite,
            duration: animationDuration,
            curve: curve,
            decoration: BoxDecoration(
              color:
                  isSelected ? item.activeColor.withOpacity(0.2) : backgroundColor,
              borderRadius: BorderRadius.circular(itemCornerRadius),
            ),
            child: Container(
              width: isSelected ? 130 : 50,
              padding: EdgeInsets.symmetric(horizontal: 10),
              child: Row(
                // mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  IconTheme(
                    data: IconThemeData(
                      size: iconSize,
                      color: isSelected
                          ? item.activeColor.withOpacity(1)
                          : item.inactiveColor == null
                              ? item.activeColor
                              : item.inactiveColor,
                    ),
                    child: item.icon,
                  ),
                  if (isSelected)
                    Expanded(
                      child: Container(
                        padding: EdgeInsets.symmetric(horizontal: 4),
                        child: DefaultTextStyle.merge(
                          style: TextStyle(
                            color: item.activeColor,
                            fontWeight: FontWeight.bold,
                          ),
                          maxLines: 1,
                          textAlign: item.textAlign,
                          child: item.title,
                        ),
                      ),
                    ),
                ],
              ),
            ),
          ),
        );
      }
    }
    
    class BottomNavyBarItem {
      BottomNavyBarItem({
        required this.screenType,
        required this.icon,
        required this.title,
        this.activeColor = Colors.blue,
        this.textAlign,
        this.inactiveColor,
      });
    
      final ScreenType screenType;
      final Widget icon;
      final Widget title;
      final Color activeColor;
      final Color? inactiveColor;
      final TextAlign? textAlign;
    }
    

    first_screen.dart

    import 'package:flutter/material.dart';
    
    class FirstScreen extends StatefulWidget {
      const FirstScreen({
        Key? key,
        required this.voidCallback,
      }) : super(key: key);
    
      final VoidCallback voidCallback;
    
      @override
      _FirstScreenState createState() => _FirstScreenState();
    }
    
    class _FirstScreenState extends State<FirstScreen> {
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Flex(
              direction: Axis.vertical,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("First Screen"),
                ElevatedButton(
                  onPressed: widget.voidCallback,
                  child: Text("Go To Forth Screen"),
                )
              ],
            ),
          ),
        );
      }
    }
    

    second_screen.dart

    import 'package:flutter/material.dart';
    
    class SecondScreen extends StatelessWidget {
      const SecondScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Second Screen"),
          ),
        );
      }
    }
    

    third_screen.dart

    import 'package:flutter/material.dart';
    
    class ThirdScreen extends StatelessWidget {
      const ThirdScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Third Screen"),
          ),
        );
      }
    }
    

    forth_screen.dart

    import 'package:flutter/material.dart';
    
    class ForthScreen extends StatelessWidget {
      const ForthScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Fourth Screen"),
          ),
        );
      }
    }
    

    home_screen.dart

    import 'package:flutter/material.dart';
    
    class HomeScreen extends StatelessWidget {
      const HomeScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Home Screen"),
          ),
        );
      }
    }
    

    messages_screen.dart

    import 'package:flutter/material.dart';
    
    class MessagesScreen extends StatelessWidget {
      const MessagesScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Messages Screen"),
          ),
        );
      }
    }
    

    profile_screen.dart

    import 'package:flutter/material.dart';
    
    class ProfileScreen extends StatelessWidget {
      const ProfileScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text("Profile Screen"),
          ),
        );
      }
    }