Posted at

FlutterでTwitterアプリみたいなスプラッシュアニメーションを作ってみる

More than 1 year has passed since last update.

ツイッターによくある、ふわっと消えていくスプラッシュアニメーションをFlutterで実装したので共有します。

イメージは下記の記事にあるようなものです。

https://qiita.com/osamu1203/items/a7c78666b18eb499c94b


完成

完成はこんな感じです。

Flutteranimation3.gif


実装


1. 一回小さくしてそのあと元に戻す

一回小さくして大きくするアニメーションを実装していきます。

AnimationControllerTween クラスを使ってイメージをアニメーションさせていきます。


AnimationController _animationController;
Animation<double> _tweenAnimation;

_setAnimation() async {
_animationController =
AnimationController(duration: Duration(milliseconds: 500), vsync: this);
_tweenAnimation =
Tween(begin: 300.0, end: 250.0).animate(_animationController);
_tweenAnimation.addListener(() => setState(() {}));
await _animationController.forward();
await _animationController.reverse();
}

@override
Widget build(BuildContext context) {
var icIcon = new AssetImage('assets/ic_icon.png');
return new Scaffold(
body: Center(
child: Image(
image: icIcon,
width: _tweenAnimation.value,
height: _tweenAnimation.value,
),
),
);
}

_setAnimation メソッドを好きなところで呼ぶとそこからアニメーションし始めます。

自分は initState() で呼んでいます。これはスプラッシュ画面なので最初の一回しか呼ばれなくていいかと思いました。

initState() 以外で呼ぶとイメージのサイズが決定できなくなってしまってエラーになるのでいい感じに調整してください

child: Image(

image: icIcon,
width: _tweenAnimation.value,
height: _tweenAnimation.value,
),

ここの部分でイメージの大きさをアニメーションにしたがって大きさを変えています。


2. フェードアウトさせる

フェードアウトは AnimatedOpacity というWidgetを使って実装します。

まずはイメージを表示しているウィジェットをラップします。


bool _visible = true;

@override
Widget build(BuildContext context) {
var icIcon = new AssetImage('assets/ic_icon.png');
return new Scaffold(
body: Center(
child: AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
child: Image(
image: icIcon,
width: _tweenAnimation.value,
height: _tweenAnimation.value,
),
),
),
);
}

Duration(milliseconds: 500) は適宜変更してください。


3. 1と2の処理を繋げていい感じにアニメーションさせる

それでは1と2のアニメーションを繋げていい感じにアニメーションさせます。


class _SplashState extends State<Splash>
with SingleTickerProviderStateMixin<Splash> {
bool isLogin = false;
AnimationController _animationController;
Animation<double> _tweenAnimation;

bool _visible = true;

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

_setAnimation();
new Future.delayed(const Duration(seconds: 1))
.then((value) => handleTimeout());
}

_setAnimation() async {
_animationController =
AnimationController(duration: Duration(milliseconds: 500), vsync: this);
_tweenAnimation =
Tween(begin: 300.0, end: 250.0).animate(_animationController);
_tweenAnimation.addListener(() => setState(() {}));
await _animationController.forward();
await _animationController.reverse();
}

@override
Widget build(BuildContext context) {
var icIcon = new AssetImage('assets/ic_icon.png');
return new Scaffold(
body: Center(
child: AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
child: Image(
image: icIcon,
width: _tweenAnimation.value,
height: _tweenAnimation.value,
),
),
),
);
}

void handleTimeout() {
setState(() {
_visible = !_visible;
});
new Future.delayed(const Duration(milliseconds: 800)).then((value) {
// ここでスプラッシュ後の画面を開かせる
});
}
}

全体のソースコードを載せました。

1、で作った小さくして大きくするアニメーションを実行します。

milliseconds: 500 で設定しているので小さくして、大きくするまでちょうど1秒なので1秒遅延後にvisibleを変更して2、でつくったフェード処理を実装しています。

正直もっといい感じにやっていきたい、、、

誰かの力になれば。