Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Side menu (Navigation rail, Navigation drawer)

Can anyone advise me how to design a very specific Side menu in flutter.

It has 2 states

  1. Collapsed (Small but icons are visible.)
  2. Expanded (Big, Icons and text)

When collapsed it is like a Navigation rail. Only icons visible.

But when expanded, it should behave like Navigation drawer. It should blur the rest of the screen, and on click outside of it it should collapse back.

I would appreciate any help. Thank you

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  bool is_expanded = false;

  int selectedPage = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: Row(
        children: [
          Stack(
            children: <Widget>[
              Container(
                color: Colors.transparent,
                margin: EdgeInsets.only(left: 120),
                width: MediaQuery.of(context).size.width - 120,
                child: BackdropFilter(
                  filter: ImageFilter.blur(sigmaX: 1, sigmaY: 1),
                  child: Opacity(
                    opacity: is_expanded ? 0.3 : 1,
                    child: Listener(
                      onPointerDown: (v) {
                        if (is_expanded) {
                          is_expanded = false;
                          setState(() {});

                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                              content: Text('Click blocked'),
                            ),
                          );
                        }
                      },
                      child: AbsorbPointer(
                        absorbing: is_expanded,
                        child: Row(
                          children: [
                            Expanded(
                              child: Container(
                                color: Colors.white,
                                child: PageHolder(selectedPage),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
              AnimatedContainer(
                duration: Duration(milliseconds: 120),
                height: double.infinity,
                width: is_expanded ? 240 : 120,
                color: Colors.blueGrey,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const SizedBox(height: 20),
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: const [
                        Text(
                          'Custom drawer',
                          style: TextStyle(
                            color: Colors.white,
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 20),
                    InkWell(
                      onTap: () {
                        setState(() => is_expanded = !is_expanded);
                      },
                      child: Row(
                        mainAxisSize: MainAxisSize.max,
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          const Text(
                            "App",
                            style: TextStyle(
                              color: Colors.white,
                            ),
                          ),
                          Icon(
                            is_expanded ? Icons.arrow_right : Icons.arrow_left,
                            color: Colors.white,
                          )
                        ],
                      ),
                    ),
                    const SizedBox(height: 20),
                    InkWell(
                      onTap: () {
                        selectedPage = 1;
                        is_expanded = false;
                        setState(() {});
                      },
                      child: Row(
                        mainAxisSize: MainAxisSize.max,
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: const [
                          Text(
                            "Page 1",
                            style: TextStyle(
                              color: Colors.white,
                            ),
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(height: 20),
                    InkWell(
                      onTap: () {
                        selectedPage = 2;
                        is_expanded = false;
                        setState(() {});
                      },
                      child: Row(
                        mainAxisSize: MainAxisSize.max,
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: const [
                          Text(
                            "Page 2",
                            style: TextStyle(
                              color: Colors.white,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  PageHolder(selectedPage) {
    switch (selectedPage) {
      case 1:
        {
          return Page1();
        }
      case 2:
        {
          return Page2();
        }

      default:
        {
          return Page1();
        }
    }
  }
}

class Page1 extends StatefulWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  State<Page1> createState() => _Page1State();
}

class _Page1State extends State<Page1> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text('Page 1 content',
      style: TextStyle(fontSize: 32),),
          const SizedBox(height: 20),
          ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(
                    content: Text('Test click'),
                  ),
                );
              },
              child: const Text('Test click'))
        ],
      ),
    );
  }
}

class Page2 extends StatefulWidget {
  const Page2({Key? key}) : super(key: key);

  @override
  State<Page2> createState() => _Page2State();
}

class _Page2State extends State<Page2> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text(
            'Page 2 content',
            style: TextStyle(fontSize: 32),
          ),
          const SizedBox(height: 20),
          ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(
                    content: Text('Test click'),
                  ),
                );
              },
              child: const Text('Test click'))
        ],
      ),
    );
  }
}```
like image 518
Nikola Jocic Avatar asked Oct 29 '25 14:10

Nikola Jocic


1 Answers

Solution ^^

include NavigationRail widget in IntrinsicWidth widget

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(

      ),
      drawer: _NavigationRailExample(),
      body: Container(),
    );
  }
}



class _NavigationRailExample extends StatefulWidget {

  const _NavigationRailExample({Key? key}) : super(key: key);
  _NavigationRailExampleState createState() => _NavigationRailExampleState();
}

class _NavigationRailExampleState extends State<_NavigationRailExample> {

  int _selectedIndex = 0;

  bool extended =false;


  Widget build(BuildContext context) {
    return SafeArea(
      child: IntrinsicWidth(
        child: NavigationRail(
          selectedIndex: _selectedIndex,
          destinations: _buildDestinations(),
          extended: extended,
          onDestinationSelected: (int index) {
            setState(() {
              _selectedIndex = index;
            });
          },

        ),
      ),
    );
  }

  List<NavigationRailDestination> _buildDestinations() {
    return [
      NavigationRailDestination(
        icon: InkWell(
          onTap: () {
            setState(() =>
            extended = !extended);
          },
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text("App"),
              Icon(extended ? Icons.arrow_right : Icons.arrow_left)
            ],
          ),
        ),
        label: Container(width: 0,) ,
      ),
      NavigationRailDestination(
        icon: Icon(Icons.home),
        label: Text('Home'),
      ),
      NavigationRailDestination(
        icon: Icon(Icons.favorite),
        label: Text('Favorites'),
      ),
      NavigationRailDestination(
        icon: Icon(Icons.logout),
        label: Text('Logout'),
      ),
    ];
  }
}
like image 50
Imen A. Avatar answered Oct 31 '25 03:10

Imen A.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!