🐱

【Flutter】Lottieを使ったanimationの実装案

2023/12/18に公開

はじめに

最近ではアプリ市場が飽和状態にあり、アプリにアニメーションを導入するかどうかは検討が必要なポイントです。確かに、アプリケーションが機能的であればアニメーションは必須ではありませんが、競争が激しくなる中で、ユーザ体験の向上が求められています。

また、アニメーションを導入するコストが低いのであれば、それが差別化や視覚的な魅力を生み出す手段となり得ます。本記事では、FlutterLottieを活用してアニメーションを導入する方法を紹介します。これにより、開発者やデザイナーは手軽かつ費用対効果の高い方法でアプリに魅力を加えることができます。

アプリにおいてアニメーションがなくても問題ない場合でも、ユーザーへの良い印象やエンゲージメント向上の可能性があることを考慮に入れつつ、アニメーションの導入を検討することは価値のある一環と言えるでしょう。

lottieとは

そもそもlotteとはなんでしょうか、ChatGPTに聞いてみます。

lottieとはなんですか?

Lottieは、エンジモブ(Airbnbのデザインエンジニアリングチーム)によって開発されたオープンソースのライブラリで、主にモバイルアプリケーションやWebアプリケーションでベクトルアニメーションを再生するために使用されます。LottieはJSON形式のアニメーションデータを使用し、高品質なアニメーションを比較的低いファイルサイズで表現できます。

Lottieは、デザイナーと開発者の協力を強化し、デザイナーが作成したアニメーションを開発者が簡単に実装できるようにすることを目的としています。以下は、Lottieの主な特徴と利点です:

プラットフォームの対応性: LottieはiOS、Android、React Native、Webなど、さまざまなプラットフォームで使用できます。これにより、異なるプラットフォームに対して一貫したアニメーションを提供できます。

高度な制御: Lottieはアニメーションの再生、一時停止、逆再生などの高度な制御を提供します。これにより、アプリ内で柔軟かつダイナミックなアニメーションを実現できます。

デザイナーと開発者の連携: LottieはAfter Effectsなどのデザインツールで作成されたJSON形式のアニメーションデータをサポートし、開発者はこれをコードで簡単に統合できます。

軽量かつ高品質なアニメーション: JSON形式のデータは比較的小さく、高品質なベクトルアニメーションを効率的に表現できます。これにより、アプリケーションのファイルサイズやパフォーマンスへの影響が最小限に抑えられます。

Flutterなどのモバイルアプリケーション開発フレームワークでは、Lottieは特にデザイナーが作成したアニメーションをアプリに組み込むための便利なツールとして広く利用されています。

要するに、Lottieはベクトルアニメーションを再生するためのオープンソースライブラリで、JSON形式のデータを使用して高品質かつ軽量なアニメーションを実現するものようです。

Figma to lottie

今回は私はFigmaを使ってLottieのアニメーションを作成しました。Figmaを使って、簡単にLottieアニメーションの作成ができます。

あくまでもLottieのFlutterへの導入例なので詳しい説明は省きます。(Figmaでのアニメーション作成をお考えの方は以下を参考ください。)
https://lottiefiles.com/jp/plugins/figma

lottieの導入

まずは使うパッケージは以下のとおりです。
https://pub.dev/packages/lottie

例にならって、パッケージを追加します。

flutter pub add lottie
pubspec.yaml
dependencies:
  lottie: ^2.7.0

これでFlutter側の準備完了です。

実装例

パッケージの公式ドキュメントを参考に、 Lottieの基本的な使用法を紹介します。

Widgetで使用する

基本的なWidgetでの使用例は以下のとおりです。

アセットフォルダにあるjsonファイルを再生する。

Lottie.asset('assets/LottieLogo1.json'),

ネット上にあるjsonファイルを再生する

Lottie.network('https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),

zipファイルでの再生も可能です。

Lottie.asset('assets/lottiefiles/angel.zip'),

AnimationControllerを用いて複雑に操作する

AnimationControllerを用いることで、複雑に操作することができます。

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  late final AnimationController _controller;

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

    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 2));
  }

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

  bool isPlay = false;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView(
          children: [
            Lottie.asset(
              'assets/LottieLogo1.json',
              controller: _controller,
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            if (isPlay) {
              setState(() {
                isPlay = !isPlay;
              });
              _controller.stop();
            } else {
              setState(() {
                isPlay = !isPlay;
              });
              _controller.repeat();
            }
          },
          child: Icon(isPlay ? Icons.stop : Icons.play_arrow),
        ),
      ),
    );
  }
}

アニメーション案

ここからは、実際にアプリに導入できそうな実装案を紹介します。

splash

スプラッシュ画面での実装案です。

コード全体
splash_screen.dart
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  
  void initState() {
    Future.delayed(const Duration(seconds: 3), () {
      Navigator.of(context).push(
        PageRouteBuilder(
          pageBuilder: (context, animation, secondaryAnimation) {
            return const HomePage();
          },
          transitionDuration: const Duration(seconds: 1),
          reverseTransitionDuration: const Duration(seconds: 1),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            final color = ColorTween(
              begin: Colors.transparent,
              end: Colors.white,
            ).animate(CurvedAnimation(
              parent: animation,
              curve: const Interval(
                0.0,
                0.5,
                curve: Curves.easeInOut,
              ),
            ));
            final opacity = Tween<double>(
              begin: 0.0,
              end: 1.0,
            ).animate(CurvedAnimation(
              parent: animation,
              // 後半
              curve: const Interval(
                0.5,
                1.0,
                curve: Curves.easeInOut,
              ),
            ));
            return AnimatedBuilder(
              animation: animation,
              builder: (context, child) {
                return Container(
                  color: color.value,
                  child: Opacity(
                    opacity: opacity.value,
                    child: child,
                  ),
                );
              },
              child: child,
            );
          },
        ),
      );
    });
    super.initState();
  }

  
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Lottie.asset('assets/splash.json'),
      ),
    );
  }
}

bottom

ボタンを押した時のアクションでの実装案です。

コード全体
home_screen.dart
class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
  late final AnimationController _controller;

  
  void initState() {
    super.initState();

    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 2));
  }

  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HomePage'),
      ),
      floatingActionButton: InkWell(
        onTap: () async {
          _controller.forward();
        },
        child: Lottie.asset(
          'assets/botton.json',
          repeat: true,
          width: 90,
          height: 90,
          controller: _controller,
        ),
      ),
    );
  }
}

loading

ローディング時の実装案です。

コード全体
home_screen.dart
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HomePage'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showGeneralDialog(
            context: context,
            barrierDismissible: false,
            transitionDuration: const Duration(milliseconds: 300),
            barrierColor: Colors.black.withOpacity(0.2),
            pageBuilder: (BuildContext context, Animation animation,
                Animation secondaryAnimation) {
              return Center(
                child: Lottie.asset(
                  'assets/loading.json',
                  repeat: true,
                  width: 100,
                  height: 100,
                ),
              );
            },
          );
          Future.delayed(
            const Duration(seconds: 4),
            () => Navigator.pop(context),
          );
        },
        child: const Icon(
          Icons.add,
        ),
      ),
    );
  }
}

最後に

ここまで読んでくださり、あいがとうございます。

以上がFlutterとLottieを組み合わせてアニメーションを導入する手法や、実際の導入事例の一部です。アプリケーションにおけるアニメーションの効果は、ユーザーエクスペリエンスの向上や視覚的な魅力の付加に寄与します。しかし、コストやコンテキストに応じて適切に活用することが重要です。

アプリの特定の場面にアニメーションを導入する際には、ユーザーの期待に応えつつも過度な使用には注意が必要です。洗練されたアニメーションはアプリに動きと生命を与えますが、過剰な使用は逆効果になりかねません。

これらの手法や実装例を参考に、プロジェクトに適した形でアニメーションを導入し、ユーザーにとって魅力的で快適なアプリケーション体験を提供することをお勧めします。アプリ開発の際には、デザインとエンジニアリングのチームが協力し、バランスの取れたアニメーションを検討することが成功の鍵となります。

参考文献

https://pub.dev/packages/lottie

https://pub.dev/packages/lottie

https://cbtdev.net/flutter-progress-indicator/

Discussion