Implicit Flutter Animations

Oct 4 2022 · Dart 2.17, Flutter 3.0, Visual Studio Code 1.7

Part 2: Implicit Animations in Action

07. Create a Card Flip Animation

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 06. Create a Custom PageView Animation Next episode: 08. Create a Multi-Selection Animation

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 07. Create a Card Flip Animation

The student materials have been reviewed and are updated as of August 2022.

The updated material uses null safety and also deploys the use coding practises encouraged by the Flutter as per the Flutter lint rules and a few addons of practises that are considered good here at raywenderlich (see analysis_options.yaml in the material for more info).

Transcript: 07. Create a Card Flip Animation

In this episode, we would be creating a card flip animation. You’ll learn how to trigger animations based on form interations. Let’s head over to the add_card_screen.

This screen contains a form and a credit card ui to show the updated data as you fill in the form. Focusing on the cvv input field shows the back of the card.

Currently, our code just swaps the front card to show a different back widget. We want to create a animation to simulate a card rotation effect whenever the cvv textfield is focused. Let’s head over to the add_card_screen.dart file to get a brief overview of the currrent code.

The two variable we would be working with is the _cvvFocusNode and _isCvvFocused. The _cvvFocusNode is a focusnode object that is used track whenever the cvv textfield is focused. While the _isCvvFocused is a boolean that tells us if the cvv textfield is focus or not.

We initialized the _cvvFocusNode inside the initState method and also added a listener that listens for focus events. The callback is quite simple. It sets the _isCvvFocused boolean to true if it is focused and to false when it doesnt have focus. And remember, we must always call setState whenever we update members of a state so that Flutter can rebuild the widget. After that, we remove the listener and dispose the focusnode object inside the dispose method. This is done to prevent memory leaks.

Then the _cvvFocusNode is asigned to the focusNode parameter of the cvv TextFormField widget. With this setup, the focusnode object tracks the focus of the cvv textformfield.

Finally, we use the _isCvvFocused boolean to check if the cvv textfield has the current focus and if it does, we show the BackCard widget else, we show the FrontCard widget. This simple logic swaps the card widgets to show.

But we want a flip animation, right? Okay, let’s do that now. Update your code to the following:

import 'dart:math' as math;
...
@override
Widget build(BuildContext context) {
    double rotationFactor = _isCvvFocused ? 1.0 : 0.0; // Add this
    ...
    // Paste this
    TweenAnimationBuilder(
        duration: const Duration(milliseconds: 1000),
        curve: Curves.fastOutSlowIn,
        tween: Tween(begin: rotationFactor, end: rotationFactor),
        builder: (context, value, child) {
        return Transform(
            transform: Matrix4.identity()
            ..setEntry(3, 2, 0.001) // perspective
            ..rotateY(math.pi * value),
            alignment: FractionalOffset.center,
            child: value < 0.5
                ? FrontCard(
                    cardNumber:
                        (formData['card_number'] as String?) ?? '-',
                    cardName: (formData['card_name'] as String?) ?? '-',
                    expiryDate: formData['expiry_date'] as DateTime?,
                )
                : BackCard(
                    cvv: (formData['cvv'] as String?) ?? '-',
                ),
        );
        },
    ),

First, we created a rotationFactor variable inside the build method. This is the going to be our animation value. So if the cvv textfield is focused then we set it to 1.0 which signifies a full rotation and if it not focused, then we set it back to 0.0 which takes it back to its original state.

We use a TAB because we dont have a built in implicit animated widget for 3d rotation. We set the begin and end values to the rotationFactor variable we created above. Remember, this values would range between 0.0 to 1.0.

Inside the builder, we return a transform widget and set it Y rotation to pi multiplied by the animation value. The y rotation signifies rotation on the horizontal axis and pi equals 180 degrees. So at 0.0, we dont have a rotation while at 1.0, we have a 180 degree rotation. And as for these magic numbers for the identity matrix, these set of numbers are commonly used and they simply handle the perspective for the transformation. Understanding how they do this is beyond the scope of this course. Just put em there and move on ;)

Next, we set the alignment to the center of the card so it takes the center of the card as the origin of its rotation. After that, we use the value produced from the TAB and return the front card if the rotation is below the midpoint else we return the backcard. This let’s us swap the cards at the midpoint which in turn gives the effect that the same card is rotating when truly we’re just changing the widgets being displayed. Okay, let’s try it out.

Ummm! okay!!! we have a flip animation but if you notice, the back card is also flipped on its y axis. And this happens because it is getting its original rotation from the frontcard’s perspective. We can simply flip it with a Transform widget. Head over to the BackCard widget and update your code like so:

class BackCard extends StatelessWidget {
  ...
  @override
  Widget build(BuildContext context) {
    return Transform(
      transform: Matrix4.identity()
        ..setEntry(3, 2, 0.001) // perspective
        ..rotateY(math.pi),
      alignment: FractionalOffset.center,
      child: Container(
          ...

We wrapped the BackCard’s Container with a Transform widget and flipped it horizontally with an angle of 180 degrees. It simply the same code like before, but this time around, we removed the rotation factor since there wont be any animation for correcting its rotation. Save your work and try it out. Cool. Everthing works fine and now you have your complete card flip animation.