Lottie で Xamarin.Forms のスプラッシュページを作ってみた.

Airbnb の Lottie が話題です.

Lottie の説明はこちらがわかりやすいです.

Lottie ですが、じつは Xamarin(Android/iOS/Forms)でも使えます!

今回は Lottie を使って Xamarin.Forms の スプラッシュページを実装してみます.

Android プロジェクト

Android では MainActivity の前に SplashActivity を一枚挟むことでスプラッシュページを実現します.

ただの画像を表示するだけならば Activity のスタイルに android:windowBackground を指定するだけでよいのですが、Lottie のアニメーションは LottieAnimationView というビューとして実装されているので、Activity のレイアウトにこちらのビューを設定することで実現します.

Resources.values.styles.xml

<?xml version="1.0" encoding="UTF-8"?>
<resources>
  <style name="MyTheme" parent="MyTheme.Base">
  </style>
	
  <style name="MyTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primaryDark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:windowBackground">@color/window_background</item>
    <item name="colorButtonNormal">@color/primary</item>
    <item name="android:textColorPrimary">@color/white</item>
    <item name="android:colorActivatedHighlight">@android:color/transparent</item>
  </style>

  <style name="Theme.Splash" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
	<item name="android:windowBackground">@drawable/bg_color</item>  
  </style>
</resources>

まず、MainActivity とは別にスプラッシュページ用のテーマを用意します.今回はフルスクリーンの設定に加えて、背景を設定しています.

背景の android:windowBackground ですが、android:colorBackground でも同様のことは行えますが、こちらだと一瞬黒い画面が表示されてしまうので、あえて android:windowBackground を使用しています.

Resources.values.colors.xml

<resources>
  <color name="primary">#2196F3</color>
  <color name="primaryDark">#1976D2</color>
  <color name="white">#FFF</color>
  <color name="black">#000</color>
  <color name="accent">#FFC107</color>
  <color name="window_background">#F5F5F5</color>
  <drawable name="bg_color">#02d1c4</drawable> 
</resources>

背景色は colors.xml に定義しています.

SplashActivity.cs

using Android.Animation;
using Android.App;
using Android.Content;
using Android.OS;
using Com.Airbnb.Lottie;

namespace LottieSample.Droid
{
    [Activity(Theme = "@style/Theme.Splash",
        MainLauncher = true,
        NoHistory = true)]
    public class SplashActivity : Activity, Animator.IAnimatorListener
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.Activity_Splash);

            var animationView = FindViewById(Resource.Id.animation_view);
            animationView.AddAnimatorListener(this);
        }

        public void OnAnimationCancel(Animator animation)
        {
        }

        public void OnAnimationEnd(Animator animation)
        {
            StartActivity(new Intent(Application.Context, typeof(MainActivity)));
        }

        public void OnAnimationRepeat(Animator animation)
        {
        }

        public void OnAnimationStart(Animator animation)
        {
        }
    }
}

SplashActivity.cs の実装です.

Animator.IAnimatorListener を継承して、アニメーション終了時に MainActivity に遷移するようにしています.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:lottie_fileName="LottieLogo1.json"
        app:lottie_autoPlay="true"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

レイアウトは上記のようになっています.

レイアウトで指定している JSON ファイルは Assets に BuildAction = “AndroidAsset” で配置しています.

実装結果です.

android:windowBackground が表示されてからアニメーションが始まるまで1秒少し遅延がありますが、おおよそいい感じかと思います.

以上が Android プロジェクトの実装です.

iOS プロジェクト

iOS も Android と同様に SplashViewController を一枚挟むことでスプラッシュページを実現します.

iOS では LaunchScreen があるので、そこに Lottie のビュー(iOS では LOTAnimationView になります)を追加すればよいかと思ったのですが、LaunchScreen にはカスタムビューを使えないという制限があったので、Android と同様に SplashViewController を用います.

AppDelegate.cs

using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using Lottie.Forms.iOS.Renderers;
using UIKit;

namespace LottieSample.iOS
{
	[Register("AppDelegate")]
	public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
	{
		public override UIWindow Window { get; set; }

		public override bool FinishedLaunching(UIApplication app, NSDictionary options)
		{
		    if (Window == null)
		    {
		        Window = new UIWindow(frame: UIScreen.MainScreen.Bounds);
		        var initialViewController = new SplashViewController();
		        Window.RootViewController = initialViewController;
		        Window.MakeKeyAndVisible();

		        return true;
		    }
		    else
		    {
		        global::Xamarin.Forms.Forms.Init();
		        AnimationViewRenderer.Init();
		        LoadApplication(new App());
		        return base.FinishedLaunching(app, options);
		    }
		}
	}
}

まず、AppDelegate です.

Window = null ならば SplashViewController に遷移します.そうでないならば Forms の初期化を行います.

using Airbnb.Lottie;
using UIKit;

namespace LottieSample.iOS
{
	public partial class SplashViewController : UIViewController
	{
		public SplashViewController() : base("SplashViewController", null)
		{
		}

		public override void ViewDidLoad()
		{
			base.ViewDidLoad();
			var animationView = LOTAnimationView.AnimationNamed("LottieLogo1");
			this.View.AddSubview(animationView);
			animationView.PlayWithCompletion((animationFinished) =>
			{
			    UIApplication.SharedApplication.Delegate.FinishedLaunching(UIApplication.SharedApplication,
				                                                           new Foundation.NSDictionary());
			});
		}

		public override void DidReceiveMemoryWarning()
		{
			base.DidReceiveMemoryWarning();
		}
	}
}

SplashViewController では、LOTAnimationView を追加し、アニメーション終了時のイベントで再度 FinishedLaunching をコールし、Forms の初期化を行います.

FinishedLaunching の引数の LaunchOptions が null の場合、NRE でクラッシュしたのでインスタンスを設定していますが、どこかにグローバル変数が定義されていませんかね?

LOTAnimationView.AnimationNamed(“LottieLogo1”) で指定した JSON ファイルはプロジェクト直下に BuildAction = “BundleResource” で配置しています.

こちらが実装結果です.

Android と同様に、LaucheScreen が表示されてから少し遅延がありますが、おおよそいい感じかと思います.

以上が iOS プロジェクトの実装です.

まとめ

今回は Lottie を使って Xamarin.Forms のスプラッシュページを実装してみました.

Lottie は高度なアニメーションを簡単に実装できるのでとても便利ですね!Xamarin.Native、Xamarin.Forms 両方で使えるのもポイント高いです.

スプラッシュページの実装としては、Android はおおよそ問題ないかと思うのですが、iOS の Forms 初期化部分はだいぶ怪しいと思っています.Forms 初期化部分で正しい実装がありましたら、教えていただけると嬉しいです.

以上です.

参考