Skip to main content

Create an Animated Stack Menu in Flutter

Animation in Flutter is really cool. There are multiple ways to do it. In this post, we are going to create an Animated stack drawer navigation. When the hamburger menu button is pressed, the main screen slide right to show the drawer.

For our menu, we’re going to use a simple Stack with items that we can position however we want. We’ll be using the animation controller to drive all the animations in our menu.

import 'package:flutter/material.dart';

class StackPage extends StatefulWidget {
  @override
  _StackPageState createState() => _StackPageState();
}

class _StackPageState extends State<StackPage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: Duration(milliseconds: 500));
    super.initState();
  }

  void _toggle() {
    setState(() {
      _controller.isDismissed ? _controller.forward() : _controller.reverse();
    });
  }

  FlatButton _menuItem(IconData icon, String text, VoidCallback onPressed){
    return FlatButton(onPressed: onPressed, child: Row(
      children: [
        Icon(icon, color: Colors.white,),
        SizedBox(width: 8,),
        Text(text, style: TextStyle(color: Colors.white),)
      ],
    ));
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (BuildContext context, Widget child) {
        double slide = 50 * _controller.value;
        double scale = 1 - (_controller.value * 0.5);
        return Stack(
          children: [
            Container(
              width: double.infinity,
              color: Colors.lightBlueAccent,
              child: Padding(
                padding: const EdgeInsets.only(
                    top: 50.0, left: 16.0, right: 16.0, bottom: 16.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            'Navigation',
                            style: Theme.of(context).textTheme.headline6,
                          ),
                          _menuItem(Icons.home, 'Home', (){}),
                          _menuItem(Icons.pages, 'Page 1', (){}),
                          _menuItem(Icons.palette, 'Page 2', (){}),
                          _menuItem(Icons.close, 'Close Menu', () => _toggle()),
                        ],
                      ),
                      flex: 5,
                    ),
                    Expanded(
                      child: Container(),
                      flex: 5,
                    )
                  ],
                ),
              ),
            ),
            Transform(
              transform: Matrix4.identity()
                ..translate(slide)
                ..scale(scale),
              alignment: Alignment.centerRight,
              child: Scaffold(
                appBar: AppBar(
                  title: Text('Example'),
                  actions: [
                    IconButton(
                      icon: Icon(Icons.dehaze),
                      onPressed: () {
                        _toggle();
                      },
                    )
                  ],
                ),
                body: Center(
                  child: Text('Main page'),
                ),
              ),
            ),
          ],
        );
      },
    );
  }
@override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

By continuing to use the site, you agree to the use of cookies.