エキサイトの武藤です。
FlutterにおけるWidgetのフェードイン・アウトアニメーションUIについて簡単に紹介します。
- Visibilityの表示・非表示の場合
- AnimatedSwitcherを使ったフェードイン・アウトのアニメーションUI
- FadeTransitionを使ったフェードイン・アウトのアニメーションUI
- 終わりに
- 採用情報
- 参考
Visibilityの表示・非表示の場合
まずは、アニメーションがない単純な表示、非表示です。 単純な表示・非表示の場合は、Visibilityで実現できます。
class _MyHomePageState extends State<MyHomePage> { bool isVisible = true; void _switchVisible() { setState(() { isVisible = !isVisible; }); } @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Visibility( visible: isVisible, child: const FlutterLogo(size: 100), ), ), floatingActionButton: FloatingActionButton( onPressed: _switchVisible, child: const Icon(Icons.touch_app), ), ); } }
図のように、素早く切り替わります。 要件によりますが、簡単なものであればこれで十分です。
AnimatedSwitcherを使ったフェードイン・アウトのアニメーションUI
今度は、フェードイン・アウトアニメーションをつけた表示・非表示をしてみます。 AnimatedSwitcherを使ってみます。
class _MyHomePageState extends State<MyHomePage> { bool isVisible = true; void _switchAnimation() { setState(() { isVisible = !isVisible; }); } @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: AnimatedSwitcher( duration: const Duration(milliseconds: 800), reverseDuration: const Duration(milliseconds: 800), child: isVisible ? const FlutterLogo( key: Key('1'), size: 100, ) : const SizedBox( key: Key('2'), ), ), ), floatingActionButton: FloatingActionButton( onPressed: _switchAnimation, child: const Icon(Icons.animation), ), ); } }
表示判定フラグでFlutterLogoと空のSizedBoxを出しわけています。
AnimatedSwitcherのchildに設定するWidgetには、一意にKeyを設定することでアニメーションが動きます。
キーを設定しない場合、フレームワークからは同じものとみなされて、パラメータの更新のみを行い、アニメーションは動きません。
FadeTransitionを使ったフェードイン・アウトのアニメーションUI
次は、FadeTransitionを使って実現します。
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { late AnimationController animationController; void _switchAnimation() { if (animationController.isCompleted) { animationController.reverse(); return; } animationController.forward(); } @override void initState() { animationController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); super.initState(); } @override void dispose() { animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final tweenAnimation = Tween(begin: 1.0, end: 0.0).animate(animationController); return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Visibility( visible: tweenAnimation.value != 0, child: FadeTransition( opacity: tweenAnimation, child: const FlutterLogo(size: 100), ), ), ), floatingActionButton: FloatingActionButton( onPressed: _switchAnimation, child: const Icon(Icons.animation), ), ); } }
FadeTransitionとVisibility を組み合わせても、フェードイン・アウトを実現できます。
こちらはAnimationControllerでアニメーションの設定や制御をできます。 凝ったことをする場合には、こちらのほうが自由が効きそうです。
終わりに
簡単な内容ですが、Flutter Wiidgetのフェードイン・アウトアニメーションUIを紹介しました。
AnimatedOpacityを使った透明化もありますが、表示領域は残ってしまいます。操作がある画面の場合、タップできてしまい、意図した挙動にならないことがあります。 AnimatedSwitcherやFadeTransitionを使った方法では、透明化と表示領域を消すことができます。 その他にも実現方法はあるかもしれません。
どなたかの参考になれば幸いです。
採用情報
エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。
参考
FadeTransitionの、opacityがゼロになったらVisibilityのvisibleがfalseになる版(透明Widgetの無駄がほぼゼロになる) · GitHub