flutterflutter-animationflutter-row

Place element of a row above other elements to hide animation


I am trying to create a Material NavigationRail that, with the click of a button on the rail, shows a drawer with secondary destinations in my app. I have a Scaffold that as a body has a Row containing the NavigationRail and a Stack. The Stack contains the actual content of my homepage as well as the drawer, but only when the button has been clicked (I use riverpod).

I want to animate the drawer in and out on button clicks, but the drawer appears on top of the NavigationRail. How do I keep the rail in front of the drawer? If I include it in the stack, the content and the drawer are shifted to the left, behind the rail, so that does not work.

Currently, the animation looks like this:

enter image description here

I made a Dartpad that reproduces the behaviour: DartPad


Solution

  • You can use only Stack with AnimatedPosition widget.

    class HomePage extends StatefulWidget {
      const HomePage({super.key});
    
      @override
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      bool drawerOpen = false;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Stack(
          children: [
            AnimatedPositioned(
              duration: const Duration(milliseconds: 200),
              left: drawerOpen ? 64 : -300,
              width: 300,
              top: 0,
              bottom: 0,
              child: const SizedBox(
                height: double.infinity,
                width: 300,
                child: ColoredBox(color: Colors.blue),
              ),
            ),
            Positioned(
              left: 0,
              top: 0,
              bottom: 0,
              width: 64,
              child: NavigationRail(
                backgroundColor: Colors.deepPurple,
                leading: IconButton(
                  icon: const Icon(Icons.menu),
                  onPressed: () {
                    setState(() {
                      drawerOpen = !drawerOpen;
                    });
                  },
                ),
                destinations: const [
                  NavigationRailDestination(
                      icon: Icon(Icons.abc), label: Text("A")),
                  NavigationRailDestination(
                      icon: Icon(Icons.ac_unit), label: Text("B"))
                ],
                selectedIndex: 1,
              ),
            ),
          ],
        ));
      }
    }