🌟

TabViewにアニメーションを実装する!!

2023/04/25に公開

1.概要

NestedScrollViewでのタブの切り替え時にアニメーションを追加します。
DefaultTabControllerにはデフォルトでインジケーターが実装されていますが、今回はタブの背景がアニメーションするようにしてみます!!

実際に実装したリポジトリはこちらから確認できます!
https://github.com/daisukemaki1003/animated-tabbar-example-flutter

2. 実装

class _TabBarDelegate extends SliverPersistentHeaderDelegate {
  const _TabBarDelegate(this.tabBar);
  
  final TabBar tabBar;

  
  double get minExtent => tabBar.preferredSize.height;

  
  double get maxExtent => tabBar.preferredSize.height;

  TabController? get controller => tabBar.controller;

  /// PageViewのスクロール量を[0~1]で取得する
  double get animationValue => controller?.animation?.value ?? 0;

  /// [0~1]で生成されるデータを[-1~1]に変換する
  double get indicatorPosition => animationValue * 2 - 1;

  /// 現在表示されているWidget
  Widget get currentWidget => tabBar.tabs[controller?.index ?? 0];

  
  Widget build(context, shrinkOffset, overlapsContent) {
    return Container(
      color: Colors.white,
      child: Stack(
        children: [
          AnimatedAlign(
            alignment: Alignment(indicatorPosition, 0),
            duration: const Duration(milliseconds: 1),
            child: Container(
              alignment: Alignment.center,
              padding: const EdgeInsets.symmetric(vertical: 8),
              width: MediaQuery.of(context).size.width / 2,
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(30),
                  color: Colors.red,
                ),
                child: Opacity(opacity: 0, child: currentWidget),
              ),
            ),
          ),
          Container(color: Colors.transparent, child: tabBar),
        ],
      ),
    );
  }

  
  bool shouldRebuild(_TabBarDelegate oldDelegate) {
    return tabBar != oldDelegate.tabBar;
  }
}

Discussion