# Advanced Animations

As you progress in your Flutter journey, you'll come across the need for more advanced animations to create a visually appealing user experience. Flutter offers a plethora of tools and libraries to help you create complex animations.

## Advanced Animation in Flutter 🎥

### 1. Animation Controller 🎛️

The `AnimationController` is a powerful tool that not only controls the animation, but also the speed, duration, and much more. It can be used to create more complex animations by controlling the behavior of the animation over time.

```dart
AnimationController controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
);
```

### 2. CurvedAnimation 🌊

`CurvedAnimation` allows you to apply a non-linear curve to an animation, which can make the movement feel more natural.

```dart
Animation curve = CurvedAnimation(
  parent: controller,
  curve: Curves.easeInOut,
);
```

### 3. Animation Sequences 📜

With `Interval`, you can control the portion of an animation's duration when a range of values is used.

```dart
Animation<double> tween = Tween<double>(begin: 0, end: 300).animate(
  CurvedAnimation(
    parent: controller,
    curve: Interval(
      0.5, 1.0,
      curve: Curves.fastOutSlowIn,
    ),
  ),
);
```

### 4. Staggered Animations 💫

Staggered animations are a sequence of animations that run one after the other.

```dart
Animation<double> tween = Tween<double>(begin: 0, end: 300).animate(
  CurvedAnimation(
    parent: controller,
    curve: Interval(
      0, 0.6,
      curve: Curves.ease,
    ),
  ),
);
```

## Let's Understand An Advanced Animation Example 🔖

{% tabs %}
{% tab title="Code" %}
```dart
// Copyright 2020 the Dart project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.

import 'dart:math';
import 'package:flutter/material.dart';

class DiscData {
  static final _rng = Random();

  final double size;
  final Color color;
  final Alignment alignment;

  DiscData()
      : size = _rng.nextDouble() * 40 + 10,
        color = Color.fromARGB(
          _rng.nextInt(200),
          _rng.nextInt(255),
          _rng.nextInt(255),
          _rng.nextInt(255),
        ),
        alignment = Alignment(
          _rng.nextDouble() * 2 - 1,
          _rng.nextDouble() * 2 - 1,
        );
}

void main() async {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true),
      home: Scaffold(
        body: Container(
          color: const Color(0xFF15202D),
          child: const SizedBox.expand(
            child: VariousDiscs(50),
          ),
        ),
      ),
    ),
  );
}

class VariousDiscs extends StatefulWidget {
  final int numberOfDiscs;

  const VariousDiscs(this.numberOfDiscs);

  @override
  State<VariousDiscs> createState() => _VariousDiscsState();
}

class _VariousDiscsState extends State<VariousDiscs> {
  final _discs = <DiscData>[];

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

  void _makeDiscs() {
    _discs.clear();
    for (int i = 0; i < widget.numberOfDiscs; i++) {
      _discs.add(DiscData());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        const Center(
          child: Text(
            'Click a disc!',
            style: TextStyle(color: Colors.white, fontSize: 50),
          ),
        ),
        GestureDetector(
          onTap: () => setState(() {
            _makeDiscs();
          }),
          child: Stack(children: [
            for (final disc in _discs)
              Positioned.fill(
                child: AnimatedAlign(
                  duration: const Duration(milliseconds: 500),
                  curve: Curves.easeInOut,
                  alignment: disc.alignment,
                  child: AnimatedContainer(
                    duration: const Duration(milliseconds: 500),
                    decoration: BoxDecoration(
                      color: disc.color,
                      shape: BoxShape.circle,
                    ),
                    height: disc.size,
                    width: disc.size,
                  ),
                ),
              ),
          ]),
        ),
      ],
    );
  }
}
```
{% endtab %}

{% tab title="Animation" %}
<figure><img src="https://522858097-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOdSyMra5vx5HbARBPAir%2Fuploads%2FCHwLsJYsiIj0tL2VUqr6%2Fezgif.com-video-to-gif%20(8).gif?alt=media&#x26;token=a6ea06ed-ea09-4978-91c2-889fcfa812b3" alt="" width="450"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Code Explanation 📖

### 1. Import Statements 📚

```dart
import 'dart:math';
import 'package:flutter/material.dart';
```

These lines import necessary libraries. The `dart:math` library is used to work with random numbers, and `package:flutter/material.dart` is the Material library in Flutter, which provides many widgets to build a UI.

### 2. DiscData Class 📀

```dart
class DiscData {
  static final _rng = Random();

  final double size;
  final Color color;
  final Alignment alignment;

  DiscData()
      : size = _rng.nextDouble() * 40 + 10,
        color = Color.fromARGB(
          _rng.nextInt(200),
          _rng.nextInt(255),
          _rng.nextInt(255),
          _rng.nextInt(255),
        ),
        alignment = Alignment(
          _rng.nextDouble() * 2 - 1,
          _rng.nextDouble() * 2 - 1,
        );
}
```

The `DiscData` class holds information for each disc, including its size, color, and position. The constructor initializes these properties with random values.

### 3. Main Function 🏁

```dart
void main() async {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true),
      home: Scaffold(
        body: Container(
          color: const Color(0xFF15202D),
          child: const SizedBox.expand(
            child: VariousDiscs(50),
          ),
        ),
      ),
    ),
  );
}
```

The `main` function is the entry point of the Flutter app. Here, a `MaterialApp` widget is created with a dark theme and a `VariousDiscs` widget with 50 discs as the home screen.

### 4. VariousDiscs Widget 🔄

```dart
class VariousDiscs extends StatefulWidget {
  final int numberOfDiscs;

  const VariousDiscs(this.numberOfDiscs);

  @override
  State<VariousDiscs> createState() => _VariousDiscsState();
}
```

The `VariousDiscs` widget is a `StatefulWidget` that takes the number of discs as a parameter.

### 5. \_VariousDiscsState Class 📊

```dart
class _VariousDiscsState extends State<VariousDiscs> {
  final _discs = <DiscData>[];

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

  void _makeDiscs() {
    _discs.clear();
    for (int i = 0; i < widget.numberOfDiscs; i++) {
      _discs.add(DiscData());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        const Center(
          child: Text(
            'Click a disc!',
            style: TextStyle(color: Colors.white, fontSize: 50),
          ),
        ),
        GestureDetector(
          onTap: () => setState(() {
            _makeDiscs();
          }),
          child: Stack(children: [
            for (final disc in _discs)
              Positioned.fill(
                child: AnimatedAlign(
                  duration: const Duration(milliseconds: 500),
                  curve: Curves.easeInOut,
                  alignment: disc.alignment,
                  child: AnimatedContainer(
                    duration: const Duration(milliseconds: 500),
                    decoration: BoxDecoration(
                      color: disc.color,
                      shape: BoxShape.circle,
                    ),
                    height: disc.size,
                    width: disc.size,
                  ),
                ),
              ),
          ]),
        ),
      ],
    );
  }
}
```

The `_VariousDiscsState` class manages the state of the `VariousDiscs` widget. It creates a list of `DiscData` objects, which are used to build a stack of animated discs. When a disc is tapped, the `_makeDiscs` method is called to regenerate the list of discs, triggering a new set of animations.

***

## Assignments 📝

* [ ] Create a Flutter app that utilizes a `CurvedAnimation`.
* [ ] Experiment with different `Curve` values to understand their impact.
* [ ] Create a staggered animation with at least three different animation sequences.

