Flutter

【Flutter】画像を裏返して別の画像を表示するアニメーションを実装する

記事内に商品プロモーションを含む場合があります

Flutterで画像を現実のカードを裏返すみたいに裏返して、別の画像を表示するという実装をしました。

画像を180度回転させたり、反転させたりというのは簡単にできますが、裏返すというのはある程度工夫しないと実現できません。

独自のWidgetを作成することで実現しているので、サンプルコードと共にご紹介します。

画像を裏返して別の画像を表示するイメージ

今回は、Flutterで画像を現実のカードを裏返すみたいに裏返して、別の画像を表示するという実装をしました。

言葉だと伝わりづらいのでイメージを貼ってみました。

このようなものを実装したので、紹介していきます。

ちなみにこのような動きのことを英語で「flip」というそうです。

調査する際に少し苦労しました。

画像を裏返して別の画像を表示する実装

今回は裏返して別の画像を表示するWidgetを作成しました。

以下のような仕様のWidgetになりました。

  • 初期表示時の画像パスを渡す(画像1)
  • 裏返したときに表示する画像のパスに入れ替える(画像2)
  • 画像1が裏返るアニメーションをしたあと、画像2を表示する

実際のソースコードは以下のとおりです。

import 'dart:math';

import 'package:flutter/material.dart';

class FlipImg extends StatefulWidget {
  final String assetPath;

  const FlipImg({Key? key, required this.assetPath}) : super(key: key);

  @override
  _FlipImgState createState() => _FlipImgState();
}

class _FlipImgState extends State<FlipImg>
    with SingleTickerProviderStateMixin {
  late String _currentImagePath;
  late String _image1;
  late String _image2;
  late AnimationController _animationController;
  final Curve _rotationCurve = Curves.elasticOut;
  double _rotation = 0.0;

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

    _image1 = widget.assetPath;
    _currentImagePath = widget.assetPath;

    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 3800),
    )
      ..addListener(_updateRotation)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _onRotationComplete();
        }
      });
  }

  @override
  void didUpdateWidget(covariant FlippingImage oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.assetPath != oldWidget.assetPath) {
      _immediatelyFinishCurrentAnimation();
      _image2 = widget.assetPath;
      _flipCard();
    }
  }

  void _flipCard() {
    _currentImagePath = _image1;
    _animationController.forward(from: 0.0);
  }

  void _immediatelyFinishCurrentAnimation() {
    if (_animationController.isAnimating) {
      _animationController.stop();
      _currentImagePath = _image2;
      _image1 = _image2;
    }
  }

  void _onRotationComplete() {
    setState(() {
      _animationController.value = 0;
      _image1 = _image2;
      _currentImagePath = _image2;
    });
  }

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

  void _updateRotation() {
    setState(() {
      _rotation = pi * _rotationCurve.transform(_animationController.value);

      if (_currentImagePath == _image1 && _rotation > pi / 2) {
        _currentImagePath = _image2;
      } else if (_currentImagePath == _image2 && _rotation < pi / 2) {
        _currentImagePath = _image1;
      } else if (_currentImagePath == _image2) {
        _rotation = _rotation - pi;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Transform(
          transform: Matrix4.identity()
            ..setEntry(3, 2, 0.001)
            ..rotateY(_rotation),
          alignment: FractionalOffset.center,
          child: ClipRRect(
            borderRadius: BorderRadius.circular(16),
            child: IntrinsicHeight(
              child: Image.asset(
                _currentImagePath,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

 

かなりいい感じです。

まとめ

Flutterのアニメーションを駆使して、画像が裏返っているような動きを実現しました。

アニメーションは慣れないと難しいですが、使いこなせるとかなりいい感じの動きを見せることができそうです。

Flutter学習情報

Flutterを勉強するのに最適な参考書は、以下の「基礎から学ぶFlutter」です。

環境構築から、Dart/Flutterの基本/テストやパフォーマンスチューニングまで一通り学ぶことができます。

また、当ブログではFlutterを初心者が学ぶためにオススメな方法を「Flutter を初心者が学ぶおすすめの勉強法!【間違いない動画があります】」という記事で公開していますので、Flutterに興味がある方は是非読んでみてください。

Flutterに入門するためのオススメ勉強法【間違いない動画があります】Flutter 初心者が勉強する場合に、最高の動画をお伝えします。...

動画学習がしたい!という方にオススメの記事がこちらです。

【Udemy】スマホアプリ作成を学ぶときに受講しておきたい講座3選【Flutter】スマホアプリを初めて作成する場合、何らかの教材を見ながら進めると思います。 私は動画で学習するのが好きで、非常に効率よく学ぶことが...

Flutterの将来性はどうなのか?をまとめた記事はこちらです。

【2021/10 更新】Flutterの将来性をトレンドやGoogleの情勢から分析した結果クロスプラットフォーム開発のフレームワークの中で近年注目されているのが「Flutter」です。 私も2020年の4月頃から注目して...