【Flutter】そのまま使えるアニメーションWidget(ImplicitlyAnimatedWidget編)

※本記事は下記のZenn本にまとめました。

https://zenn.dev/cxj/books/07def04506182d

# ImplicitlyAnimatedWidget家族
ImplicitlyAnimatedWidget は抽象です。その親子関係は下記です。ImplicitlyAnimatedWidget家族は`SingleTickerProviderStateMixin`の継承いらなくなりました。
```dart
...
class _AnimatedContainerPageState extends State<AnimatedContainerPage> {
...
```

```dart
ImplicitlyAnimatedWidget [abstract]
|---AnimatedContainer
|---AnimatedPadding
|---AnimatedAlign
|---AnimatedPositioned
|---AnimatedPositionedDirectional
|---AnimatedScale
|---AnimatedRotation
|---AnimatedSlide
|---AnimatedOpacity
|---SliverAnimatedOpacity
|---AnimatedDefaultTextStyle
|---AnimatedPhysicalModel
|---TweenAnimationBuilder
|---AnimatedTheme
```

# ImplicitlyAnimatedWidget使用例

## AnimatedContainer
**Container** 内の各属性をアニメーション化できるため、非常に実用的です。アニメーションの時間`duration` を設定し、アニメーションの曲線`curve` やアニメーションの終了時に呼び出されるコールバック`onEnd` を設定することができます。これらの設定は**ImplicitlyAnimatedWidget** で共通しています。

```dart
  AnimatedContainer({
    Key? key,
    this.alignment,
    this.padding,
    Color? color,
    Decoration? decoration,
    this.foregroundDecoration,
    double? width,
    double? height,
    BoxConstraints? constraints,
    this.margin,
    this.transform,
    this.transformAlignment,
    this.child,
    this.clipBehavior = Clip.none,
    Curve curve = Curves.linear,
    required Duration duration,
    VoidCallback? onEnd,
  })
```

下記の例では`Container`の高さ、枠線、色のグラデーションアニメーションです。
[animated_container_page.dart](https://github.com/ling350181/flutter_ui/blob/main/lib/animation/implicitly_animated_widget/animated_container_page.dart)

<img src=https://storage.googleapis.com/zenn-user-upload/26ada5776f3a-20230315.gif width=300>

## AnimatedAlign
AnimatedWidget家族の[AlignTransition](https://qiita.com/ling350181/items/91772ca3bd9cd5071da4#aligntransition) の使い方基本は同じです。

```dart
 const AnimatedAlign({
    Key? key,
    required this.alignment,
    this.child,
    this.heightFactor,
    this.widthFactor,
    Curve curve = Curves.linear,
    required Duration duration,
    VoidCallback? onEnd,
  })
```

[animated_align_page.dart](https://github.com/ling350181/flutter_ui/blob/main/lib/animation/implicitly_animated_widget/animated_align_page.dart)

<img src=https://storage.googleapis.com/zenn-user-upload/e8c70bc8acba-20230315.gif width=300>

## AnimatedOpacity
**AnimatedOpacity** は、子Widgetの透明度のグラデーションアニメーションを実行させることができます。透明度値の`opacity` とアニメーションの時間`duration` を渡す必要があります。また、アニメーションの曲線curveやアニメーションの終了時に呼び出されるコールバック`onEnd`を設定することもできます。`child`には、透明度のグラデーションアニメーションを適用したい子Widgetを指定します。

```dart
  const AnimatedOpacity({
    Key? key,
    this.child,
    required this.opacity,
    Curve curve = Curves.linear,
    required Duration duration,
    VoidCallback? onEnd,
    this.alwaysIncludeSemantics = false,
  })
```

[animated_opacity_page.dart](https://github.com/ling350181/flutter_ui/blob/main/lib/animation/implicitly_animated_widget/animated_opacity_page.dart)

<img src=https://storage.googleapis.com/zenn-user-upload/a7b7c9464a67-20230315.gif width=300>


## TweenAnimationBuilder
**TweenAnimationBuilder** では、`tween` と `builder` callBack builderを渡す必要があります。`Tween` の変化に応じて、builder callBackが呼び出され、Widgetが再構築され、アニメーションが実行されます。ImplicitlyAnimatedWidget家族は１４個しかないから、それ以外の属性をアニメーションしたい場合は**TweenAnimationBuilder** を使いましょう。

```dart
  const TweenAnimationBuilder({
    Key? key,
    required this.tween,
    required Duration duration,
    Curve curve = Curves.linear,
    required this.builder,
    VoidCallback? onEnd,
    this.child,
  })
```

下記の例では**TweenAnimationBuilder** で**AnimatedAlign** と同じ効果のアニメーションを作りました。`builder` callBackで位置属性`AlignmentGeometry`の変化でアニメーションを実現させました。

```dart
return Scaffold(
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              height: 300,
              width: 300,
              color: Colors.lightGreen,
              child: TweenAnimationBuilder(
                duration: const Duration(milliseconds: 2000),
                tween: tween,
                builder: (_, AlignmentGeometry alignment, child) {
                  return Align(
                    alignment: alignment,
                    child: const Icon(
                      Icons.ac_unit,
                      color: Colors.red,
                      size: 25,
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
```

[tween_animation_builder_page.dart](https://github.com/ling350181/flutter_ui/blob/main/lib/animation/implicitly_animated_widget/tween_animation_builder_page.dart)

<img src=https://storage.googleapis.com/zenn-user-upload/e8c70bc8acba-20230315.gif width=300>