Flutter Flare 2D Animation Basics

Whenever I see an awesome UI element in a native app my first question is How do I make that in Flutter?. That’s exactly what I asked when I downloaded the Giphy Android app recently, which has runs a colorful and fun animation for each icon in the bottom navbar.

These animations are complex. Hypothetically, they could be created in Flutter natively with a custom painter, but that would be very challenging and painful. Thankfully, we have Flare 2D a design tool that makes it easy to create complex animations with vector graphics and run them in Flutter’s rendering engine at 60+ FPS.

Part 1: Create Animated Icons with Flare 2D

Access the files used in this lesson on my Flare profile or from the project github repo.

First, we need to create some awesome animated graphics with Flare. Create a free account, then complete the tasks below. These tasks represent the skills you need to have in Flare to re-create Giphy’s animated icons.

I highly recommend memorizing the following hotkeys.

  • T translate or move shapes around.
  • S scale or resize shapes.
  • R rotate shapes.
  • Hold space to drag around the screen.
  • ctrl+Z to undo.

Draw a Shape

Flare provides a basic set of design tools that we can use to draw vector graphics. You can also design your graphics in a different tool, like Figma or Sketch for example, then import them into Flare.

Tasks

  1. Draw a basic star shape using the star tool.
  2. Center it on the artboard and have it take up as much space on the Y axis as possible.
  3. Remove the stroke and adjust the fill color.
Draw a star

Draw a star

Animate the Fill Color

We can animate almost anything on the shape. Let’s get familiar with the animation timeline by animating the color of the star from gray to yellow.

Tasks

  1. Switch to animation mode.
  2. Change the untitled animation name to go (this will be important when we get the Flutter code).
  3. Create a keyframe by selecting the diamond next to the fill control.
  4. Scrub the timeline to the end and change the fill color. A new keyfame would be added automatically.
  5. Press play. You just created an animation.
Animate the fill color of the star

Animate the fill color of the star

Animate Transformations - Translate, Scale, Rotate

An easy way to bring your shapes to life is by animating size, movement, and rotation angle.

Tasks

  1. Create keyframes for rotation and scale.
  2. Adjust the key interpolation to make to ease the timing.
Animate the rotation of the star and change the key interpolation to cubic

Animate the rotation of the star and change the key interpolation to cubic

Animate the Shape

We can also animate the verticies of the star to to transform it into a completely different shape.

Tasks

  1. Add a keyframe to edit verticies.
  2. Click “edit verticies”, scrub to a different time, move the verticies to automatically add a keyframe.
Use the verticies to change and animate the points of the shape

Use the verticies to change and animate the points of the shape

Animate the Stroke for a Hand-Drawn Effect

Stroke animations make it easy to look like you are drawing a shape by hand.

Tasks

  1. Give the shape a stroke.
  2. Set the end of the stroke to 0% until it is invisible.
  3. Animate the end value to give it a drawing effect.
Animate the stroke end from 0% to 100%

Animate the stroke end from 0% to 100%

Animate the Position in a Clipping Mask

Clipping masks allow you to make shapes disappear behind another shape. A clipping mask is like installing a window on the house - you can only see the contents inside its boundaries.

Tasks

  1. Create a new shape that covers the star.
  2. Select the star, then click clipping box, then select the new shape.
  3. Go into animation mode and animate the position of the star.
Create another shape to serve as a clipping box for the star.

Create another shape to serve as a clipping box for the star.

Part 2 - Flutter Flare Integration

Flare provides package that makes it dead simple to use our animations into an iOS or Android app with Flutter. Run to flutter create your_project to get started. The end goal is to build a usable animated icon navigation menu like the demo below:

Add flare_flutter to pubspec.yaml

Add flare_flutter to the pubspec.yaml.

file_type_light_yaml build.yaml
dependencies:
  flutter:
    sdk: flutter

  flare_flutter: any


flutter:
  uses-material-design: true
  assets:
   - assets/  

Export your Animations to Flutter

Export the animations to a folder named assets in the root of your project.

Export the binary file from Flare

Export the binary file from Flare

Define a Class for the Menu Item

There are many different ways to build a menu in flutter, but we’re going to build our navigation menu from scratch. The data for each menu item can be abstracted into a class.

  • name is the filename of the .flr asset
  • color controls the line above the icon
  • x is the X-axis alignment of the item (-1 is far left, 1 is far right).
file_type_dartlang main.dart
class MenuItem {
  final String name;
  final Color color;
  final double x;
  MenuItem({this.name, this.color, this.x});
}

Animating the Colored Top Bar

Our navigation menu is wrapped in a StatefulWidget to keep track of the currently selected item. Here’s a breakdown of each important line of code.

  1. Set a default menu item on initState.
  2. Define a Stack. The first element is an container for the colored , while the second item is the navigation menu row..
  3. Create an AnimatedContainer that takes up 20% of the screen width and is aligned to the active menu item.
  4. Define a Row to hold the Flare graphics that uses spaceAround alignment on the main axis.
file_type_dartlang main.dart
class NavBar extends StatefulWidget {
  createState() => NavBarState();
}

class NavBarState extends State<NavBar> {
  List items = [
    MenuItem(x: -1.0, name: 'house', color: Colors.lightBlue[100]),
    MenuItem(x: -0.5, name: 'planet', color: Colors.purple),
    MenuItem(x: 0.0, name: 'camera', color: Colors.greenAccent),
    MenuItem(x: 0.5, name: 'heart', color: Colors.pink),
    MenuItem(x: 1.0, name: 'head', color: Colors.yellow),
  ];

  MenuItem active;

  @override
  void initState() {
    super.initState();

    active = items[0]; // <-- 1. Activate a menu item
  }

  @override
  Widget build(BuildContext context) {
    double w = MediaQuery.of(context).size.width;
    return Container(
      height: 80,
      color: Colors.black,
      child: Stack(    //  <-- 2. Define a stack
        children: [
          AnimatedContainer(  //  <-- 3. Animated top bar
            duration: Duration(milliseconds: 200),
            alignment: Alignment(active.x, -1),
            child: AnimatedContainer(
              duration: Duration(milliseconds: 1000),
              height: 8,
              width: w * 0.2,
              color: active.color,
            ),
          ),
          Container(  // <-- 4. Main menu row
            child: Row(   
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: items.map((item) {
                return _flare(item);  // <-- 5. Flare graphic will go here
            ),
          )
        ],
      ),
    );
  }

}

Animating the Flare Graphics

In this final section, we define a method that will turn the Flare animations into tap-able buttons that change the state of the widget. This can be achieved with a setState call from a GestureDetector, as we do not want Material ink splashes in this demo.

The FlareActor is a widget from the flare_flutter package that that will run the specified animation when the state changes.

Remember, we defined the animation name as go in the Flare editor before exporting the file. By default, the animation name is Untitled.

file_type_dartlang main.dart
  Widget _flare(MenuItem item) {
    return GestureDetector(
      child: AspectRatio(
        aspectRatio: 1,
        child: Padding(
          padding: EdgeInsets.only(top: 20),
          child: FlareActor(
            'assets/${item.name}.flr',
            alignment: Alignment.center,
            fit: BoxFit.contain,
            animation: item.name == active.name ? 'go' : 'idle',
          ),
        ),
      ),
      onTap: () {
        setState(() {
          active = item;
        });
      },
    );
  }

Questions? Let's chat

Open Discord