3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Flutter】ListViewのアイテムを外からアニメーションさせる【Animation】

Last updated at Posted at 2022-07-08

問題点

ボタンが押された時に、ListViewの特定のアイテムをアニメーションさせたい。

アイテムをタップでアニメーションは簡単にできるんだけど、ボタンタップ時に外からアニメーションさせるにはひと工夫必要だった。
今回は、ボタンが押されたら特定のアイテムのOpacityを変更して、点滅しているように見えるアニメーションを実装するよ。
完成形はこんな感じ。

コードは簡略化しているので、コピペだと動かないよ。
サンプルあるから、ここから持っていってね。

解決策

GlobalObjectKeyを使えば実現できる。
3ステップで解説していくよ。

1. Listを持つWidgetに対してGlobalObjectKeyを設定する。

まず、Listを持つWidgetに対してGlobalObjectKeyを設定する。
そうすると、key経由でSampleListが持つ関数を実行できるようになる。

// Todo
final listKey = GlobalObjectKey<SampleListState>(context);

return Scaffold(
  body: SampleList(
      // Todo
      key: listKey,
      nameList: nameList,
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // Todo
      listKey.currentState?.animate(5);
    },
  ),
);

2. リストのアイテムにGlobalObjectKeyを設定する。

次に、リストのアイテムにGlobalObjectKeyを設定する。
initState()の時に、受け取ったリストの分だけfor文を回して、keyを生成していく。
itemのビルド時に、indexを元にして取得したkeyを渡す。

これで、ボタンが押された時にkey経由でアニメーションの関数を実行できるようになる。

class SampleList extends StatefulWidget {
  const SampleList({super.key, required this.nameList});

  final List<String> nameList;

  @override
  State<StatefulWidget> createState() => SampleListState();
}

class SampleListState extends State<SampleList> {
  
  // Todo
  final List<GlobalObjectKey<SampleListItemState>> keys = [];

  @override
  void initState() {
    super.initState();
    // Todo
    for (var name in widget.nameList) {
      keys.add(GlobalObjectKey(name));
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemBuilder: (context, index) {
        // Todo
        return SampleListItem(key: keys[index], name: widget.nameList[index]);
      },
      itemCount: widget.nameList.length,
    );
  }

  // Todo
  void animate(int index) {
    keys[index].currentState?.animate();
  }
}

3. リストのアイテムを実装する。

最後に、アニメーションできるアイテムを実装する。

class SampleListItem extends StatefulWidget {
  const SampleListItem({super.key, required this.name});

  final String name;

  @override
  State<StatefulWidget> createState() => SampleListItemState();
}

class SampleListItemState extends State<SampleListItem>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 200),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final opacityAnimation = Tween<double>(
      begin: 1.0,
      end: 0.3,
    ).animate(_animationController);

    var opacityAnimationCounter = 0;
    _animationController.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _animationController.reverse();
      } else if (status == AnimationStatus.dismissed) {
        if (opacityAnimationCounter < 2) {
          _animationController.forward();
          opacityAnimationCounter++;
        } else {
          opacityAnimationCounter = 0;
        }
      }
    });

    return FadeTransition(
      opacity: opacityAnimation,
      child: Container(
        color: Colors.teal,
        padding: const EdgeInsets.all(16),
        child: Text(widget.name),
      ),
    );
  }

  void animate() {
    _animationController.forward();
  }
}

ボタンが押されると、リストのアイテムのanimate()が呼び出されて、アニメーションが実行される。

まとめ

  • GlobalObjectKeyを使うと、子要素の関数を実行できる。
  • GlobalObjectKeyのリストを生成して保持しておくことで、リストの特定のアイテムに対してアニメーションを実行することができる。

おわり。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?