Implicit Flutter Animations

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

Part 2: Implicit Animations in Action

08. Create a Multi-Selection 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: 07. Create a Card Flip Animation Next episode: 09. Animate an Item Switcher

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: 08. Create a Multi-Selection 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: 08. Create a Multi-Selection Animation

So far, we’ve seen how to select and animate a sigle item. In this episode, we would learn how to create a multi selection animation. This is a common feature in many apps and we would cover both the setup and the animation.

Let’s head over to the meal detail page. In here, we have an Extras section which is used to add some items to your meal order. And below it, we have a section that displays your selection.

Let’s take a look at what our current code looks like. In the MealScreen class, we have a _selectedExtras variable which holds a list of extras. It is currently empty. We need a way to populate it when an extra item is clicked.

Let’s head down to where the ExtraItem widget is used. The code is straightforward: we have a horizontal ListView with all the extra items displayed in it. And right below it, we have the section that displays the list of selected items in a chip.

Let’s head over to the ExtraItem widget. We need a way to add our selection to the list and animate our selection while clicking on the extra item.

There our various widgets that could be used to add interactivity in our Flutter apps. I’ll be using the InkWell widget which adds a ripple effect when clicked. Go ahead and update your code to the following:

class ExtraItem extends StatefulWidget {
  final Extra extra;
  final ValueChanged<bool> onSelected;

  const ExtraItem({Key? key, required this.extra, required this.onSelected}) : super(key: key);
...

class _ExtraItemState extends State<ExtraItem> {
    bool _isSelected = false;
    @override
    Widget build(BuildContext context) {
        return InkWell(
            onTap: () {
                setState(() {
                    _isSelected = !_isSelected;
                    widget.onSelected(_isSelected);
                });
            },
            child: Container(
                ...

First, we added the onSelected callback as a member of our stateful widget. This makes it a property of the ExtraItem class and would be implemented where this widget is used. The function takes a signature used by methods that reports that an undelying value has changed. It takes a single value which is a boolean variable for our usecase. (Duplicate on a new line and do it) We could simply replace the signature with: final Function(bool) but the one used here is more descriptive.

Next, we declared the _isSelected variable and set it to false by default. This variable would be used to know if an ExtraItem is selected.

After that, we wrapped our Container with the InkWell widget and implemented its onTap method. Inside it, we simply toggle the _isSelected variable and also call the onSelected() method of the stateful widget and passed the _isSelected variable as its boolean value.

What we just did here is a way of lifting state up. This is a common pattern in reactive programming. We simply expose a function as a property that would be called when this widget is clicked. We pass a boolean value to this function from inside this widget. And this value can be used by its parent to do something, in our case, adding to the selectedExtras list. Okay, let’s head over to where it is used in its parent widget. Update your code to the following:

ExtraItem(
    extra: extras[i],
    onSelected: (bool value) {
        if (value) {
            _selectedExtras.add(extras[i]);
        } else {
            _selectedExtras.remove(extras[i]);
        }
        setState(() {});
    },
)

In here, we implemented the onSelected callback method that is triggered whenever an extraitem is clicked. We use the boolean value passed from inside the widget to do a conditional check. If it is true, we add that extra to the selectedExtras list, else we remove it from the list. This creates an item toggle effect. After that, we call setState to inform Flutter that we need to rebuild the widget with the updated changes. Save your work and try it out.

Cool, it updates the _selectedExtras list accordingly. We achieved this by implementing the logic in the parent widget and executing the onSelected function inside the ExtraItem widget.

This is a simple example of lifting state up. For a deeper widget tree, you’ll want to use something like an InheritedWidget or the provider package. Okay, now we have our multi-selection logic complete, let’s head over back to the ExtraItem widget and add some animation. For this, we want to animate in a circular border and also make the text bold. Update your code to the following:

child: Column(
    children: [
        AnimatedContainer(
            duration: const Duration(milliseconds: 500),
            padding: const EdgeInsets.all(24),
            decoration: BoxDecoration(
                shape: BoxShape.circle,
                border: _isSelected
                    ? Border.all(
                        color: colorScheme.secondary,
                        width: 2,
                        )
                    : null,
            ),
            child: Image.asset(
                ...
            ),
        ),
        AnimatedDefaultTextStyle(
            duration: const Duration(milliseconds: 500),
            style: TextStyle(
              color: Colors.black,
              fontWeight: _isSelected ? FontWeight.w600 : FontWeight.normal,
            ),
            child: Text(
              widget.extra.name,
            ),
        ),
    ],
),

We updated the Container to an AnimatedContainer and gave it a BoxDecoration. We gave it a circular shape and toggled the border based on if the ExtraItem is selected.

Finally, we use the AnimatedDefaultTextStyle to style the fontWeight weight of the text. We make it bold if it is selected. Save your work and try it out.

You can see the subtle animation and notice, the item moves down a bit when selected. This is because it has a fixed width and the border grows to take some additional space when animating in.

On a closing note, if you’re wondering why we did not animate the chips entrance and exit below. Well, there is a widget that could do that. It is not an implicitly animated widget. It is the AnimatedList widget and we covered it the the Flutter ListView course.