Back to blog
March 29, 2024
4 min read

Flutter Drawer Menu Navigation

Slide-in menu for navigation

Flutter Drawer Menu Navigation

A drawer menu is a common navigation pattern in mobile applications that provides easy access to different sections of your app. This guide will show you how to implement a beautiful and functional drawer menu in Flutter.

Why Use a Drawer Menu?

Drawer menus offer several advantages:

  • Clean and organized navigation
  • Easy access to main sections
  • Consistent user experience
  • Space-efficient design
  • Familiar to users
  • Scalable navigation structure

Implementation Steps

  1. Create Drawer Menu

    class CustomDrawer extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: [
              DrawerHeader(
                decoration: BoxDecoration(
                  color: Theme.of(context).primaryColor,
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    CircleAvatar(
                      radius: 30,
                      backgroundImage: AssetImage('assets/profile.jpg'),
                    ),
                    SizedBox(height: 10),
                    Text(
                      'John Doe',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18,
                      ),
                    ),
                    Text(
                      'john.doe@example.com',
                      style: TextStyle(
                        color: Colors.white70,
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              ),
              ListTile(
                leading: Icon(Icons.home),
                title: Text('Home'),
                onTap: () {
                  Navigator.pop(context);
                  Navigator.pushNamed(context, '/home');
                },
              ),
              ListTile(
                leading: Icon(Icons.person),
                title: Text('Profile'),
                onTap: () {
                  Navigator.pop(context);
                  Navigator.pushNamed(context, '/profile');
                },
              ),
              ListTile(
                leading: Icon(Icons.settings),
                title: Text('Settings'),
                onTap: () {
                  Navigator.pop(context);
                  Navigator.pushNamed(context, '/settings');
                },
              ),
              Divider(),
              ListTile(
                leading: Icon(Icons.logout),
                title: Text('Logout'),
                onTap: () {
                  // Handle logout
                },
              ),
            ],
          ),
        );
      }
    }
    
  2. Implement in Scaffold

    class HomeScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Home'),
          ),
          drawer: CustomDrawer(),
          body: Center(
            child: Text('Home Screen Content'),
          ),
        );
      }
    }
    
  3. Add Navigation Routes

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Drawer Navigation Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          initialRoute: '/',
          routes: {
            '/': (context) => HomeScreen(),
            '/profile': (context) => ProfileScreen(),
            '/settings': (context) => SettingsScreen(),
          },
        );
      }
    }
    
  4. Create Screen Components

    class ProfileScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Profile'),
          ),
          drawer: CustomDrawer(),
          body: Center(
            child: Text('Profile Screen Content'),
          ),
        );
      }
    }
    
    class SettingsScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Settings'),
          ),
          drawer: CustomDrawer(),
          body: Center(
            child: Text('Settings Screen Content'),
          ),
        );
      }
    }
    

Advanced Features

  1. Animated Drawer

    class AnimatedDrawer extends StatefulWidget {
      @override
      _AnimatedDrawerState createState() => _AnimatedDrawerState();
    }
    
    class _AnimatedDrawerState extends State<AnimatedDrawer>
        with SingleTickerProviderStateMixin {
      late AnimationController _controller;
      late Animation<double> _animation;
    
      @override
      void initState() {
        super.initState();
        _controller = AnimationController(
          duration: Duration(milliseconds: 300),
          vsync: this,
        );
        _animation = CurvedAnimation(
          parent: _controller,
          curve: Curves.easeInOut,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            return Transform.translate(
              offset: Offset(-200 * (1 - _animation.value), 0),
              child: CustomDrawer(),
            );
          },
        );
      }
    }
    
  2. Custom Drawer Header

    class CustomDrawerHeader extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.all(16),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [
                Theme.of(context).primaryColor,
                Theme.of(context).primaryColor.withOpacity(0.8),
              ],
            ),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  CircleAvatar(
                    radius: 30,
                    backgroundImage: AssetImage('assets/profile.jpg'),
                  ),
                  SizedBox(width: 16),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'John Doe',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      Text(
                        'Premium Member',
                        style: TextStyle(
                          color: Colors.white70,
                          fontSize: 14,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ],
          ),
        );
      }
    }
    
  3. Drawer with Categories

    class CategoryDrawer extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: [
              CustomDrawerHeader(),
              ExpansionTile(
                leading: Icon(Icons.category),
                title: Text('Categories'),
                children: [
                  ListTile(
                    title: Text('Category 1'),
                    onTap: () {
                      // Handle category 1
                    },
                  ),
                  ListTile(
                    title: Text('Category 2'),
                    onTap: () {
                      // Handle category 2
                    },
                  ),
                ],
              ),
              // Add more drawer items
            ],
          ),
        );
      }
    }
    

Best Practices

  1. Navigation Structure

    • Organize menu items logically
    • Use clear and concise labels
    • Implement proper navigation flow
    • Handle back navigation
  2. User Experience

    • Add visual feedback
    • Implement smooth animations
    • Use consistent styling
    • Provide clear indicators
  3. Performance

    • Optimize drawer rendering
    • Handle state efficiently
    • Implement proper caching
    • Manage memory usage

Common Use Cases

  1. Main Navigation

    • Home screen
    • Profile section
    • Settings page
    • Help/Support
  2. Content Organization

    • Categories
    • Favorites
    • Recent items
    • Search
  3. User Features

    • Account management
    • Preferences
    • Notifications
    • Logout

Conclusion

Implementing a drawer menu in Flutter provides an intuitive and user-friendly navigation experience. By following these guidelines and implementing the provided examples, you can create a professional and functional drawer menu that enhances your app’s usability and navigation structure.