ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms】XAMLからアニメーションを使えるライブラリを作りました

この記事は「Xamarin Advent Calendar 2015 - Qiita」の5日目です。

Xamarin.Formsにはコントロールを動かしたり、汎用アニメーションを作成するのための拡張メソッドが用意されています。(Xamarin.Forms.ViewExtensionsクラス内)

// Labelコントロールを拡縮させる例
await label.ScaleTo(0.8);
await label.ScaleTo(1);

そうです、コードビハインド必須です。でも、Viewの事はXAMLで完結させたいですよね。

という訳でXAMLでアニメーションを定義、起動するためのライブラリ、 XFXamlAnimations (GitHub)という物を作りました。

インストールするにはNuGetパッケージマネージャで XFXamlAnimations と検索するか、コンソールの方で次のようにコマンドを実行してください。

PM> Install-Package XFXamlAnimations 

使い方

WPFのStoryBoardを参考にしたので何となくそれっぽい使い勝手に仕上がっています。

StoryBoardの子要素にAnimationを追加、BeginStoryBoardトリガーアクションでアニメーションを起動という寸法です。

基本サンプル

まず、AppクラスのコンストラクタXFXamlAnimations.XamlAnimations.Init(); を呼んであげてください。

public App()
{
    XFXamlAnimations.XamlAnimations.Init();
    MainPage = new MyPage();
}

これが何故必要か?

XAML側でしかライブラリを参照していない場合、最終的なアプリパッケージにライブラリが含まれないのです。そのためC#側にライブラリを参照するコードを(本当は必要なくても)入れなきゃならない訳です。(【Xamarin.Forms】自作ライブラリのカスタムコントロール使用時にSystem.IO.FileNotFoundExceptionが発生する場合の対処 - ぴーさんログ 参照)

続いてXAML側、xmlns:xa="clr-namespace:XFXamlAnimations;assembly=XFXamlAnimations"ContentPage.Content以下をごそっとコピー&ペーストすれば動きます。インテリセンスが効かないので潔くコピペしましょう。

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xa="clr-namespace:XFXamlAnimations;assembly=XFXamlAnimations"
             x:Class="Sample.MyPage">
    <ContentPage.Content>
        <!-- ボタンクリック時にボタンを回転させるサンプル -->
        <Button x:Name="button" Text="Begin animation">
            <Button.Triggers>
                <EventTrigger Event="Clicked">
                    <xa:BeginStoryBoard>
                        <xa:BeginStoryBoard.StoryBoard>
                            <xa:ParallelStoryBoard>
                                <xa:RelRotateToAnimation Target="{x:Reference button}"
                                                         Rotation="360"
                                                         Duration="1000"
                                                         Easing="BounceOut" />
                            </xa:ParallelStoryBoard>
                        </xa:BeginStoryBoard.StoryBoard>
                    </xa:BeginStoryBoard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </ContentPage.Content>
</ContentPage>

実行すると...

f:id:ticktack623:20151202022522g:plain

XAMLだけでアニメーションできちゃいました。ステキ!

主要クラスの解説

BeginStoryBoard

いわゆるTriggerActionです、EventTriggerなどと組み合わせて使いましょう。StoryBoardプロパティにセットされたアニメーションを実行します。このプロパティはBindingできない普通のCLRプロパティなので、サンプルのようにぶら下げて定義するか、PageのStaticResourceを参照しましょう。

<!-- StaticResouceで参照する例 -->
<xa:BeginStoryBoard StoryBoard="{StaticResource storyBoardKey}" />

StoryBoard

XFXamlAnimationsのStoryBoardは2種類あります。子要素には各種AnimationとStoryBoardを持たせることができます。また、Delayプロパティを設定するとアニメーションの開始を遅延させることができます。(ミリ秒)

  • ParallelStoryBoard : 子アニメーションを並列に実行する
  • SequentialStoryBoard : 子アニメーションを順番に実行する

Parallel animation

<!-- 2つのBoxViewを同時に回転させる例 -->
<xa:ParallelStoryBoard>
    <xa:RelRotateToAnimation Target="{x:Reference box1}"
                             Rotation="-360"
                             Duration="1000" />
    <xa:RelRotateToAnimation Target="{x:Reference box2}"
                             Rotation="360"
                             Duration="1000" />
</xa:ParallelStoryBoard>

Sequential animation

<!-- BoxViewを回転させた後、逆方向に回転させる例 -->
<xa:SequentialStoryBoard>
    <xa:RelRotateToAnimation Target="{x:Reference box1}"
                             Rotation="-360"
                             Duration="1000" />
    <xa:RelRotateToAnimation Target="{x:Reference box2}"
                             Rotation="360"
                             Duration="1000" />
</xa:SequentialStoryBoard>

Animation

大別して2種類あります。1つはプロパティベースなAnimation、これはWPFのDoubleAnimatonのように対象プロパティ、開始値、終了値を指定する物です。もう1つは Xamarin.Forms.ViewExtentions の拡張メソッドを呼ぶ物です。

Property-based animaton

現状、 ColorAnimationDoubleAnimation があります。

プロパティ一覧

  • Target (必須)
    • 対象コントロールに x:Name で名前を付け、 x:Reference で参照しましょう。
  • TargetPropertyName (必須)
    • 変化させるプロパティの名前
  • From (必須)
  • To (必須)
    • 終了値
  • Delay (オプション)
    • アニメーション開始の遅延時間(ミリ秒)
  • Duration (オプション)
    • アニメーションの継続時間(ミリ秒)
  • Easing (オプション)
    • アニメーションのイージング、 Xamarin.Forms.Easing に定義されている名前付きEasingが同じ名前で指定できます。

サンプル

<!-- BoxViewのカラーを変化させるサンプル -->
<xa:ColorAnimation Target="{x:Reference box1}"
                   TargetPropertyName="Color"
                   From="Blue"
                   To="Green"
                   Duration="1500" />

<!-- BoxViewの幅を変化させるサンプル、Easing指定付き -->
<xa:DoubleAnimation Target="{x:Reference box1}"
                    TargetPropertyName="WidthRequest"
                    From="130"
                    To="260"
                    Duration="1000"
                    Easing="CubicOut" />

ViewExtentions animaton

Xamarin.Forms.ViewExtentions の拡張メソッドで定義されているアニメーションに対応しています。TargetPropertyNameプロパティが存在せず、From、Toプロパティの代わりに下記括弧内のプロパティを指定します。他はプロパティベースのAnimationと同様です。

  • FadeToAnimation (Opacity)
  • LayoutToAnimation (Bounds)
  • RelRotateToAnimation (Rotation)
  • RelScaleToAnimation (Scale)
  • RotateToAnimation (Rotation)
  • RotateXToAnimation (Rotation)
  • RotateYToAnimation (Rotation)
  • ScaleToAnimation (Scale)
  • TranslateToAnimation (X and Y)

インテリセンス...

現状、Xamarin StudioのXAMLでカスタムコントロールのインテリセンスを出す方法が無さげです。(Visual Studioの方は *.Design.dllを作ればいけるかも)

せっかくXAML向けライブラリを作ったのにこれでは辛い...という訳でXamarin StudioのXAMLでカスタムコントロールのインテリセンスを出す方法を探しています。情報お持ちの方は @ticktackmobile までお知らせください。