Drawer Animation in Flutter
By: Payam Asefi
Tags: Flutter Ui, Flutter Widget, Flutter Animation, Flutter

First lets take a look at the project structure before adding animations:

home_form.dart

@override

Widget build(BuildContext context) {

return Stack(

children: [

// Works as Drawer

Scaffold(

backgroundColor: const Color(0xff22a6b3),

body:const DrawerData(),

),



// Works as Main Screen

Scaffold(

backgroundColor:Colors.white,

appBar: PreferredSize(

preferredSize: Size.fromHeight(200),

child: Container(

color: const Color(0xffee5253),

child: Padding(

padding: const EdgeInsets.fromLTRB(12, 24, 12, 12),

child: Column(

crossAxisAlignment: CrossAxisAlignment.start,

mainAxisAlignment: MainAxisAlignment.start,

children: [

IconButton(

icon: Icon(Icons.menu),

),

Padding(

padding: const EdgeInsets.only(top: 24,bottom: 12),

child: Text('Welcome',style: Theme.of(context).textTheme.headline4,),

),

const Text('Improve your language skill

by selecting one of the following languages',

style: TextStyle(

fontSize: 17,

fontStyle: FontStyle.italic

),)

],

),

),

),

),

body: const DummyData(),

) ],

);

}

We have a Stack with two child, the first one works as the drawer and the second one works as the main page. Without the animation and movement we can only see the second child on screen:

And the result we want is something like this:

In order to achieve this goal we should:

Make main screen smaller.

Move the main screen to the right.

Create a smooth transition.

Make main screen smaller

Transform is a widget that applies a transformation before painting its child, you can find more about this widget in here. So lets wrap our main content with a Transform widget:

Stack(

children: [

Scaffold(

backgroundColor: const Color(0xff22a6b3),

body:const DrawerData(),

),

Transform(

transform: Matrix4.identity()

..scale(0.6),

alignment: Alignment.center,

child: Scaffold(),

)

],

);

The transform is the matrix to transform the child during painting and by using scale we made the child 60% of the real size, if you want to find out more about 4D Matrix take a look at this codemagic post. Now our app must look like this:

flutter drawer animation

Move the main screen to the right

Moving the screen is not a hard task, with the help of previously created Tranform widget we move our child widget:

final rightSlide = MediaQuery.of(context).size.width * 0.6;

... transform: Matrix4.identity()

..translate(rightSlide)

..scale(0.6),

We should consider that changing the order of the transform value may change the result

And the current state of the app:

Create a smooth transition

To make a smooth transition to the right side of the screen we need AnimationController , it’s a class to handle animations like:

Play an animation forward or in reverse, or stop an animation.

Set the animation to a specific value.

Define the upperBound and lowerBound values of an animation.

Create a fling animation effect using a physics simulation.

To handle duration and vsync we also need to use a Mixin :

class _HomeFormState extends State<HomeForm>

with SingleTickerProviderStateMixin { AnimationController _animationController;



@override

void initState() {

super.initState();

_animationController =

AnimationController(vsync: this, duration: Duration(milliseconds: 300));

} @override

void dispose() {

_animationController.dispose();

super.dispose();

}

vsync allows us to mute, slow or fast forward our animations.

We also need a method to handle the open/close animation:

_toggleAnimation() {

_animationController.isDismissed

? _animationController.forward()

: _animationController.reverse();

}

Where:

Forward: Starts running this animation forwards (towards the end).

Reverse: Starts running this animation in reverse (towards the beginning).

Now all we need is wrap our Stack with a AnimatedBuilder and change the scale and translate value with the _animationController related value, so:

return AnimatedBuilder(

animation: _animationController,

builder: (context,child){

// Related Scale and Translate values

double slide = rightSlide*_animationController.value;

double scale = 1-(_animationController.value*0.3);



return Stack(

children: [

Scaffold(

backgroundColor: const Color(0xff22a6b3),

body:const DrawerData(),

),

Transform(

transform: Matrix4.identity()

..translate(slide)

..scale(scale),

alignment: Alignment.center,

child: Scaffold(),

)

],

);

},

);

We also change the drawer menu icon with an AnimatedIcon for a better UI design:

IconButton(

onPressed: ()=>_toggleAnimation(),

icon: AnimatedIcon(

icon: AnimatedIcons.menu_close,

progress: _animationController,

),

)

And that’s all we need for a smooth transition:

You can find the final code on Github!