Animating Apps With Flutter

Shubham

著者について

昼はフルスタックのソフトウェア開発者、夜はモバイルアプリ開発者として活躍する。 仕事以外の時間は、料理やPCゲームをするのが好きです。More aboutShubham↬

  • 14 min read
  • Apps,Animation
  • Saved for offline reading
  • Share on Twitter.com
  • Share on Twitter.com

Share on Twitter.com LinkedIn

Flutter はクロスプラットフォーム アプリに素晴らしいアニメーション サポートを提供します。 この記事では、アプリにアニメーションを追加する従来の方法とは異なる、より簡単な方法を探ります。 これらの新しい「アニメーションとモーション」ウィジェットは一体何なのか、また、シンプルなアニメーションや複雑なアニメーションを追加するためにどのように使用できるのか。

あらゆるプラットフォームのアプリケーションは、直感的で見栄えが良く、ユーザーのインタラクションに心地よいフィードバックを提供する場合に賞賛されます。 アニメーションは、まさにそれを行う方法の 1 つです。

Flutter はクロスプラットフォーム フレームワークで、過去 2 年間で Web とデスクトップのサポートを含むまでに成熟しました。 このフレームワークで開発されたアプリケーションはスムーズで見栄えが良いという評判を集めています。 豊富なアニメーションのサポート、UI を宣言的に記述する方法、「ホット リロード」、その他の機能により、Flutter は今や完全なクロスプラットフォーム フレームワークです。

Flutter を使い始め、アニメーションを追加する従来にない方法を学びたいなら、まさにうってつけの場所です:ここではアニメーションとアニメーション追加の暗黙の方法であるモーション ウィジェットの領域を探求します。 アプリの各ビジュアル コンポーネントはウィジェットであり、Android のビューと同じだと考えてください。 FlutterはAnimationクラス、管理用の「AnimationController」オブジェクト、データの範囲を補間する「Tween」を使ってアニメーションのサポートを提供します。 この3つのコンポーネントが連動して、スムーズなアニメーションを実現します。 アニメーションの作成と管理を手動で行う必要があるため、明示的なアニメーション方法として知られています。

では、アニメーションとモーションのウィジェットについて紹介します。 Flutter は、アニメーションを本質的にサポートする多数のウィジェットを提供します。 すべてのアニメーションはこのカテゴリのウィジェットによって処理されるので、アニメーションオブジェクトやコントローラを作成する必要はありません。 必要なアニメーションに適切なウィジェットを選び、ウィジェットのプロパティ値を渡すだけでアニメーションさせることができます。 このテクニックはアニメーションの暗黙的な方法です。

Animation hierarchy in Flutter.Flutterのアニメーション階層。 (Large preview)

上の図は、Flutter のアニメーション階層を大まかに示したもので、明示的および暗黙的なアニメーションがどのようにサポートされているかが示されています。

この記事で取り上げたアニメーション ウィジェットの一部は次のとおりです:

  • AnimatedOpacity
  • AnimatedCrossFade
  • AnimatedAlign
  • AnimatedPadding
  • AnimatedSize
  • AnimatedPositioned

Flutter は定義済みのアニメーション ウィジェットだけでなく、AnimatedWidget という汎用ウィジェットも提供し、これを使用して暗黙的にアニメーションするカスタム ウィジェットを作成することができます。 名前から明らかなように、これらのウィジェットはアニメーションおよびモーション ウィジェット カテゴリに属しているため、アニメーションをよりスムーズで見栄えのよいものにするための共通のプロパティをいくつか持っています。

  • duration
    パラメータをアニメーション化する期間。
  • reverseDuration
    逆アニメーションの期間。 補間された値は、線形分布から取得されるか、または指定された場合、曲線から取得されます。

「Quoted」と呼ぶシンプルなアプリを作成して、旅を始めましょう。 このアプリは、アプリが起動するたびに、ランダムな引用文を表示します。 注: これらの例のファイルはすべて GitHub にあります。

Getting Started

Flutter がインストールされており、次に進む前に基本フローに慣れている必要があります。 Android Studio で新しい Flutter プロジェクトを作成します。

New flutter project menu in Android Studio.を参照してください。 (拡大図)

新規プロジェクトウィザードを開き、プロジェクトの基本設定を行います。

Flutter プロジェクトの種類選択画面です。 (Large preview)

プロジェクトタイプ選択画面では、Flutterプロジェクトにはさまざまなタイプがあり、それぞれ特定のシナリオに対応したものです。 このチュートリアルでは、Flutter Applicationを選択してNextを押します。

ここで、プロジェクト固有の情報を入力する必要があります:プロジェクト名とパス、会社のドメインなど。 下の画像を見てください。

Flutter アプリケーションの設定画面。 (大きなプレビュー)

プロジェクト名、Flutter SDKパス、プロジェクトの場所、およびオプションのプロジェクトの説明を追加します。 Nextを押します。

Flutter アプリケーションのパッケージ名画面です。 (大きなプレビュー)

各アプリケーション (Android または iOS である) には、固有のパッケージ名が必要です。 通常、Web サイトのドメインの逆数を使用します。たとえば、com.google や com.yahoo のようにします。 Finish を押して、動作する Flutter アプリケーションを生成します。

生成されたサンプル プロジェクトです。 (大きなプレビュー)

プロジェクトが生成されると、上のような画面が表示されます。 main.dartファイル(スクリーンショットでハイライトされている)を開いてください。 これはメインのアプリケーションファイルです。

main.dart ファイルの内容を次のコード スニペットに置き換えます。

import 'package:animated_widgets/FirstPage.dart';import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Animated Widgets', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, accentColor: Colors.redAccent, ), home: FirstPage(), ); }}

このコードは、新しいアプリの作成に関連する簡単な情報を追加するだけで main.dart ファイルをクリーンアップします。 MyApp クラスはオブジェクト、つまり MaterialApp ウィジェットを返し、マテリアル デザインに準拠したアプリを作成するための基本的な構造を提供します。 コードをより構造化するために、lib フォルダ内に 2 つの新しい dart ファイルを作成します。 FirstPage.dart と Quotes.dart です。

The FirstPage.dart ファイル。 (大きなプレビュー)

FirstPage.dart には、Quoted アプリに必要なすべての視覚的要素 (ウィジェット) を担当するすべてのコードが含まれています。 すべてのアニメーションはこのファイルで処理されます。

注: 記事後半では、各アニメーション ウィジェットのすべてのコード スニペットが、Scaffold ウィジェットの子としてこのファイルに追加されています。 詳細については、GitHub 上のこの例が役に立つでしょう。

次のコードを FirstPage.dart に追加することから始めます。 これは、他のものが後で追加される部分的なコードです。

import 'dart:math';import 'package:animated_widgets/Quotes.dart';import 'package:flutter/material.dart';class FirstPage extends StatefulWidget { @override State createState() { return FirstPageState(); }}class FirstPageState extends State with TickerProviderStateMixin { bool showNextButton = false; bool showNameLabel = false; bool alignTop = false; bool increaseLeftPadding = false; bool showGreetings = false; bool showQuoteCard = false; String name = ''; double screenWidth; double screenHeight; String quote; @override void initState() { super.initState(); Random random = new Random(); int quoteIndex = random.nextInt(Quotes.quotesArray.length); quote = Quotes.quotesArray; } @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( appBar: _getAppBar(), body: Stack( children: , ), ); }}
Quotes.dart ファイルです。 (Large preview)

Quotes.dart ファイルは、ハードコードされたすべての引用符のリストを含んでいます。 ここで注意すべき点は、リストが静的オブジェクトであることです。 これは、Quotesクラスの新しいオブジェクトを作成することなく、他の場所で使用することができることを意味します。

class Quotes { static const quotesArray = ;}

プロジェクトのスケルトンができたので、Quoted をもう少し詳しく説明します。

AnimatedOpacity

アプリにパーソナルなタッチを加えるために、ユーザーの名前を知っていると良いので、それを要求して次のボタンを表示します。 ユーザーが名前を入力するまで、このボタンは非表示になり、名前が入力されると、優雅に表示されます。 ボタンの表示には何らかのアニメーションが必要ですが、そのためのウィジェットはないのでしょうか? はい、あります。

Enter AnimatedOpacity。 このウィジェットは、暗黙的なアニメーションのサポートを追加することによって、Opacity ウィジェットをベースにしています。 どのように使用するのですか? シナリオを思い出してください: アニメーション化された可視性で次へボタンを表示する必要があります。

_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Opacity animation of next button.Flutterは残りを処理します。 (大きなプレビュー)

AnimatedOpacityウィジェットには2つの必須プロパティがあります:

  • opacity
    1 の値は完全に見えることを示し、0(ゼロ)は非表示を示します。 アニメーションの間、Flutterはこの2つの極値間の値を補間します。
  • child
    表示がアニメーション化される子ウィジェット。

これで、暗黙ウィジェットで表示アニメーションを追加するのがいかに簡単かを理解できたと思います。 また、このようなウィジェットはすべて同じガイドラインに従っているため、簡単に使用できます。 次に進みましょう。

AnimatedCrossFade

ユーザーの名前がありますが、ウィジェットはまだ入力を待っている状態です。 前のステップで、ユーザーが名前を入力すると、next ボタンを表示しました。 ここで、ユーザーがボタンを押すと、入力の受け付けを停止して、入力された名前を表示したいと思います。 もちろん、いろいろな方法がありますが、入力ウィジェットを隠して、編集不可能なテキストウィジェットを表示することもできます。 AnimatedCrossFade ウィジェットを使って試してみましょう。

このウィジェットは、何らかの条件に基づいてウィジェット間でクロスフェードするため、2 つの子ウィジェットが必要です。 このウィジェットを使用する際に注意すべき重要な点は、両方の子の幅が同じでなければならないことです。 高さが異なる場合、背の高い方のウィジェットは下から切り取られます。

_getAnimatedCrossfade() { return AnimatedCrossFade( duration: Duration(seconds: 1), alignment: Alignment.center, reverseDuration: Duration(seconds: 1), firstChild: _getNameInputWidget(), firstCurve: Curves.easeInOut, secondChild: _getNameLabelWidget(), secondCurve: Curves.easeInOut, crossFadeState: showNameLabel ? CrossFadeState.showSecond : CrossFadeState.showFirst, );}
入力ウィジェットと名前ウィジェットの間のクロスフェード処理。 (Large preview)

This widget requires a different set of mandatory parameters:

  • crossFadeState
    This state works out which child to show.
  • firstChild
    Specifies the first child for this widget.This state works out the children to show.The child of this widget.
  • secondChild
    2番目の子を指定します。

AnimatedAlign

この時点で、名前ラベルは画面の中央に配置されます。 引用符を表示するために画面の中心が必要なので、上部にある方が見栄えが良くなります。 簡単に言うと、名前ラベルウィジェットの配置を中央から上に変更する必要があります。 そして、この配置の変更を、先ほどのクロスフェード・アニメーションと一緒にアニメーション化できたらいいと思いませんか?

いつものように、これを実現するためにいくつかのテクニックを使用することができます。 名前ラベル ウィジェットはすでに中央揃えにされているので、その配置をアニメーション化することは、ウィジェットの top および left 値を操作するよりもはるかに簡単でしょう。 AnimatedAlign ウィジェットは、この作業に最適です。

このアニメーションを開始するには、トリガーが必要です。 このウィジェットの唯一の目的は、配置の変更をアニメーション化することなので、いくつかのプロパティしかありません: 子を追加し、その配置を設定し、配置の変更をトリガーすること、それだけです。 (拡大図)

このウィジェットには 2 つの必須プロパティしかありません。

  • child:
    配置を変更する子。
  • alignment:
    必須の配置値。 さらに、2 つの異なるアニメーション ウィジェットを使用して、より複雑なアニメーションを簡単に作成できることを確認しました。 これがアニメーション ウィジェットの美点です。

    AnimatedPadding

    これで、上部にあるユーザーの名前が、異なる種類のアニメーション ウィジェットを使用して、それほど苦労せずに滑らかにアニメーション化されました。 名前の前に「こんにちは」という挨拶を追加してみましょう。 上部に「こんにちは」という値を持つテキスト ウィジェットを追加すると、下の画像のように、挨拶のテキスト ウィジェットに重なります。

    挨拶と名前のウィジェットが重なっています。 (大きいサイズのプレビュー)

    名前のテキスト ウィジェットの左にパディングがあった場合はどうでしょうか。 左のパディングを増やすと確かにうまくいきますが、ちょっと待ってください。何らかのアニメーションでパディングを増やすことはできないでしょうか。 そう、それがAnimatedPaddingが行うことである。 見栄えをよくするために、greeting テキスト ウィジェットがフェードインし、同時に name テキスト ウィジェットのパディングが増加するようにします。

    _getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}

    上のアニメーションは、前のアニメーションの配置が完了してから発生するので、このアニメーションをトリガーするのを遅らせる必要があります。 トピックから少し脱線しますが、これは、遅延を追加するための一般的なメカニズムについて話す良い機会です。 Flutterはそのような技術をいくつか提供していますが、Future.delayedコンストラクタはよりシンプルでクリーン、そして読みやすいアプローチのひとつです。 たとえば、1 秒後にコードの一部を実行する場合、

    Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});

    遅延時間はすでに知られているので (以前のアニメーション時間から計算)、この間隔の後にアニメーションをトリガーできます。

    // Showing "Hi" after 1 second - greetings visibility trigger._showGreetings() { Future.delayed(Duration(seconds: 1), () { setState(() { showGreetings = true; }); });}// Increasing the padding for name label widget after 1 second - increase padding trigger._increaseLeftPadding() { Future.delayed(Duration(seconds: 1), () { setState(() { increaseLeftPadding = true; }); });}
    Name ウィジェットのパッド アニメーションを実行します。 (大きなプレビュー)

    このウィジェットは、2 つの必須プロパティのみを持ちます:

    • child
      パディングが適用されるこのウィジェット内の子ウィジェット。

    AnimatedSize

    今日、ある種のアニメーションを持つアプリケーションは、ユーザーの注意を引くために視覚コンポーネントにズームインまたはズームアウトすることがあります (一般にスケーリング アニメーションと呼ばれます)。 ここで同じテクニックを使ってみてはどうでしょうか。 画面の中心からズームインして、ユーザーにやる気を起こさせるような引用を見せることができます。 AnimatedSize ウィジェットを紹介します。このウィジェットは、子ウィジェットのサイズを変更することにより、ズームインおよびズームアウト効果を有効にします。 Flutter が “Ticker” と呼ぶものが必要です。 Flutterには、新しいフレームイベントがトリガーされたときにオブジェクトに知らせるためのメソッドがあります。 これは、「今すぐやれ!」というシグナルを送るものと考えることができます。 … Do it now! … Do it now! …”

    AnimatedSize ウィジェットは、ティッカー プロバイダを受け入れるプロパティ – vsync – を必要とします。 ティッカー プロバイダーを取得する最も簡単な方法は、クラスに Mixin を追加することです。 2 つの基本的なティッカー・プロバイダの実装があります。 SingleTickerProviderStateMixin は単一のティッカーを提供し、TickerProviderStateMixin は複数のティッカーを提供します。

    ティッカーのデフォルトの実装は、アニメーションのフレームをマークするために使用されます。 この場合、後者が採用されます。 mixin の詳細。

    // Helper method to create quotes card widget._getQuoteCardWidget() { return Card( color: Colors.green, elevation: 8.0, child: _getAnimatedSizeWidget(), );}// Helper method to create animated size widget and set its properties._getAnimatedSizeWidget() { return AnimatedSize( duration: Duration(seconds: 1), curve: Curves.easeInOut, vsync: this, child: _getQuoteContainer(), );}// Helper method to create the quotes container widget with different sizes._getQuoteContainer() { return Container( height: showQuoteCard ? 100 : 0, width: showQuoteCard ? screenWidth - 32 : 0, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text(quote, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),), ), ), );}// Trigger used to show the quote card widget._showQuote() { Future.delayed(Duration(seconds: 2), () { setState(() { showQuoteCard = true; }); });}
    quotes ウィジェットのスケーリング・アニメーション。 (Large preview)

    Mandatory properties for this widget:

    • vsync
      The required ticker provider to coordinate animation and frame changes.<
    • child
      which size changes will be animated.The child is which size changes.

    ズームインとズームアウトのアニメーションが簡単に手なずけられるようになりました。

    AnimatedPositioned

    素晴らしい! 引用符は、ユーザーの注意を引くために中央からズームインします。 ズームインしながら下から上にスライドしたらどうでしょう。 試してみましょう。 この動作では、引用ウィジェットの位置を弄り、位置プロパティの変化をアニメーションで表現します。 AnimatedPositioned が最適な候補です。

    このウィジェットは、指定された位置が変更されるたびに、指定された期間にわたって子プロセスの位置を自動的に遷移させます。 注意すべき点は、その親ウィジェットが “スタック” である場合にのみ動作することです。 このウィジェットは、かなりシンプルでわかりやすい使い方ができます。

    // Helper method to create the animated positioned widget.// With position changes based on "showQuoteCard" flag._getAnimatedPositionWidget() { return AnimatedPositioned( duration: Duration(seconds: 1), curve: Curves.easeInOut, child: _getQuoteCardWidget(), top: showQuoteCard ? screenHeight/2 - 100 : screenHeight, left: !showQuoteCard ? screenWidth/2 : 12, );}
    Position with scaling animation of quotes.を参照してください。 (大きなプレビュー)

    このウィジェットは、必須プロパティが 1 つだけあります:

    • child
      位置を変更するウィジェット。

    子ウィジェットのサイズが位置とともに変化しない場合、このウィジェットに代わるより高性能なウィジェットは SlideTransition です。

    ここに完全なアニメーションがあります。 (大きなプレビュー)

    結論

    アニメーションはユーザー エクスペリエンスに不可欠な要素です。 静的なアプリや不自然なアニメーションのアプリは、ユーザーの定着率を下げるだけでなく、結果を出すための開発者の評判も下げます。

    今日、ほとんどの人気アプリには、ユーザーを喜ばせる何らかの微妙なアニメーションがあります。 また、ユーザーの要求に対するアニメーションのフィードバックは、ユーザーの興味を引き、さらに探求させることができます。 Flutter は、スムーズで応答性の高いアニメーションの豊富なサポートなど、クロスプラットフォーム開発のための多くの機能を提供します。

    Flutter には素晴らしいプラグイン サポートがあり、他の開発者のアニメーションを使用することが可能です。 コミュニティからの多くの愛情を受け、バージョン 1.9 まで成熟した今、Flutter は今後さらに良くなっていくに違いありません。 Flutterを学ぶには、今が絶好の機会だと言えるでしょう!

Leave a Reply