page.title=カスタム アニメーションの定義 @jd:body

このレッスンでの学習内容

  1. タッチ フィードバックをカスタマイズする
  2. 出現エフェクトを使用する
  3. アクティビティ遷移をカスタマイズする
  4. ビューの状態遷移にアニメーションを付ける
  5. ベクター型ドローアブルにアニメーションを付ける

関連ドキュメント

マテリアル デザインのアニメーションは、ユーザーの操作に応じて反応し、アプリの操作にともない連続した動きを見せます。 マテリアル テーマでは、ボタンやアクティビティの遷移にデフォルトのアニメーションが用意されており、Android 5.0(API レベル 21)以降では次のようなアニメーションをカスタマイズして新しいアニメーションを作成できます。

タッチ フィードバックをカスタマイズする

マテリアル デザインのタッチ フィードバックは、ユーザーが UI 要素に触れて操作した時点で、視覚的な反応を瞬時に表します。 ボタンに対するデフォルトのタッチ フィードバック アニメーションでは、新しい {@link android.graphics.drawable.RippleDrawable} クラスを使用して、状態の切り替わりをリップル(波紋)効果で表現しています。

ほとんどの場合、次のようにビューの背景を指定することでビュー XML にこの機能を適用できます。

注: selectableItemBackgroundBorderless は API レベル 21 で導入された新しい属性です。

または、ripple 要素を使って {@link android.graphics.drawable.RippleDrawable} を XML リソースとしても定義できます。

{@link android.graphics.drawable.RippleDrawable} オブジェクトには、色を割り当てることができます。タッチ フィードバックのデフォルトの色を変更するには、テーマの android:colorControlHighlight 属性を使用します。

詳細については、API リファレンスの {@link android.graphics.drawable.RippleDrawable} クラスをご覧ください。

出現エフェクトを使用する

Reveal(出現)アニメーションを使用すると、UI 要素のグループを表示したり非表示にしたりするときに連続した印象をユーザーに与えます。 {@link android.view.ViewAnimationUtils#createCircularReveal ViewAnimationUtils.createCircularReveal()} メソッドでは、ビューを表示したり非表示にしたりする際に円形のアニメーションを付けることができます。

この効果を使って、非表示のビューを表示するには:

// previously invisible view
View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());

// create the animator for this view (the start radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);

// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();

この効果を使って、表示されているビューを非表示にするには:

// previously visible view
final View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the initial radius for the clipping circle
int initialRadius = myView.getWidth();

// create the animation (the final radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);

// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        myView.setVisibility(View.INVISIBLE);
    }
});

// start the animation
anim.start();

アクティビティ遷移をカスタマイズする

図 1 - 共有要素を使った画面遷移。

端末の画像をクリックすると動画を再生できます

マテリアル デザイン アプリの Activity transitions (アクティビティ遷移)では、共通する要素の間での動作や変化を通じて、状態の切り替えに視覚的なつながりを持たせます。 Enter と Exit の遷移や、アクティビティ間での Shared elements 遷移にカスタム アニメーションを指定できます。

Android 5.0(API レベル 21)では、次の Enter 遷移と Exit 遷移がサポートされています。

{@link android.transition.Visibility} クラスを拡張する Transition はすべて、EnterTransition または ExitTransition としてサポートされます。 詳細については、API リファレンスの {@link android.transition.Transition} クラスをご覧ください。

Android 5.0(API レベル 21)では、次の共有要素遷移もサポートしています。

アプリにアクティビティ遷移を適用すると、アクティビティの開始と終了の間でデフォルトのクロス フェーディング遷移が有効になります。

  図 2 - 1 つの共有要素とシーンの遷移。

カスタム遷移を指定する

まず、マテリアル テーマから継承したスタイルを定義するときに、android:windowContentTransitions 属性で windowContentTransitions を有効にします。また、次のように Enter、Exit、Shared Element の Transitions をスタイルの定義で指定できます。

<style name="BaseAppTheme" parent="android:Theme.Material">
  <!-- enable window content transitions -->
  <item name="android:windowContentTransitions">true</item>

  <!-- specify enter and exit transitions -->
  <item name="android:windowEnterTransition">@transition/explode</item>
  <item name="android:windowExitTransition">@transition/explode</item>

  <!-- specify shared element transitions -->
  <item name="android:windowSharedElementEnterTransition">
    @transition/change_image_transform</item>
  <item name="android:windowSharedElementExitTransition">
    @transition/change_image_transform</item>
</style>

この例の change_image_transform 遷移は、次のように定義されています。

<!-- res/transition/change_image_transform.xml -->
<!-- (see also Shared Transitions below) -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
  <changeImageTransform/>
</transitionSet>

changeImageTransform 要素は {@link android.transition.ChangeImageTransform} クラスに対応します。詳細については、API リファレンスの {@link android.transition.Transition} をご覧ください。

代わりに、コードで windowContentTransitions を有効にするには、 {@link android.view.Window#requestFeature Window.requestFeature()} メソッドを呼び出します。

// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// set an exit transition
getWindow().setExitTransition(new Explode());

コードで遷移を指定するには、{@link android.transition.Transition} オブジェクトで次のメソッドを呼び出します。

{@link android.view.Window#setExitTransition setExitTransition()} と {@link android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} メソッドは、呼び出し元のアクティビティの ExitTransition を定義します。 {@link android.view.Window#setEnterTransition setEnterTransition()} と {@link android.view.Window#setSharedElementEnterTransition setSharedElementEnterTransition()} メソッドは、呼び出し先のアクティビティの EnterTransition を定義します。

遷移の効果を完全に表すには、呼び出し元と呼び出し先のアクティビティ双方で windowContentTransitions を有効にする必要があります。 有効にしていないと、呼び出し元のアクティビティが Exit 遷移を開始したあと、window 遷移(スケールやフェードなど)が起きます。

Enter 遷移をできるだけ早く開始するには、呼び出し先のアクティビティで {@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} メソッドを使用します。これにより、さらに印象的な Enter 遷移になります。

遷移を使ってアクティビティを開始する

遷移を有効にしてアクティビティで ExitTransition を設定した場合、次のように別のアクティビティを開始したときに Exit 遷移がアクティベートされます。

startActivity(intent,
              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

2 つ目のアクティビティに EnterTransition を設定している場合は、そのアクティビティの開始時に Enter 遷移も発生します。 別のアクティビティ開始時の遷移を無効にするには、null のオプション バンドルを付与します。

共有要素を使ってアクティビティを開始する

共有要素を持つ 2 つのアクティビティの間で画面遷移のアニメーションを作成するには:

  1. テーマで windowContentTransitions を有効にします。
  2. スタイルで SharedElementsTransition を指定します。
  3. 遷移を XML リソースとして定義します。
  4. android:transitionName 属性を用いて、双方のレイアウトで共有要素に同じ名前を割り当てます。
  5. {@link android.app.ActivityOptions#makeSceneTransitionAnimation ActivityOptions.makeSceneTransitionAnimation()} メソッドを使用します。
// get the element that receives the click event
final View imgContainerView = findViewById(R.id.img_container);

// get the common element for the transition in this activity
final View androidRobotView = findViewById(R.id.image_small);

// define a click listener
imgContainerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, Activity2.class);
        // create the transition animation - the images in the layouts
        // of both activities are defined with android:transitionName="robot"
        ActivityOptions options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
        // start the new activity
        startActivity(intent, options.toBundle());
    }
});

コードで生成した共有の動的ビューでは、 {@link android.view.View#setTransitionName View.setTransitionName()} メソッドを使用して両方のアクティビティに共通の要素名を指定します。

2 つ目のアクティビティが終了したときにシーンの切り替えアニメーションを逆回転させるには、{@link android.app.Activity#finish Activity.finish()} の代わりに {@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} メソッドを呼び出します。

複数の共有要素を使ってアクティビティを開始する

複数の共有要素を持つ 2 つのアクティビティの間にシーンの切り替えアニメーションを付けるには、双方のレイアウトで android:transitionName 属性を使用(または双方のアクティビティで {@link android.view.View#setTransitionName View.setTransitionName()} メソッドを使用)して共有要素を定義して、次のように {@link android.app.ActivityOptions} オブジェクトを作成します。

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(view1, "agreedName1"),
        Pair.create(view2, "agreedName2"));

曲線モーションを使用する

マテリアル デザインのアニメーションは、時間的な間を補ったり立体的な動作パターンを表現するために曲線を多く用いています。 Android 5.0(API レベル 21)以降では、カスタムのタイミングで描かれる曲線や曲線モーションのパターンをアニメーションで定義できます。

{@link android.view.animation.PathInterpolator} クラスはベジェ曲線や {@link android.graphics.Path} オブジェクトに基づく新しい Interpolator(補間)です。 この Interpolator は 1x1 の正方形に動作曲線を指定します。アンカー ポイントは(0,0)と(1,1)、制御点はコンストラクタ引数を使用して指定します。 または、PathInterpolator を XML リソースとしても定義できます。

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:controlX1="0.4"
    android:controlY1="0"
    android:controlX2="1"
    android:controlY2="1"/>

マテリアル デザインの仕様では、次の 3 つの基本的な曲線を XML リソースとして提供しています。

{@link android.view.animation.PathInterpolator} オブジェクトは {@link android.animation.Animator#setInterpolator Animator.setInterpolator()} メソッドに渡すことができます。

{@link android.animation.ObjectAnimator} クラスには新しいコンストラクタがあり、一度に 2 つ以上のプロパティを使用して経路に沿ったアニメーションを作ることができます。 たとえば、次の animator では {@link android.graphics.Path} オブジェクトを使ってビューの X と Y プロパティを指定しています。

ObjectAnimator mAnimator;
mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
...
mAnimator.start();

ビューの状態遷移にアニメーションを付ける

{@link android.animation.StateListAnimator} クラスを使って、ビューの状態が変化したときに実行されるアニメーションを定義できます。 次の例は、{@link android.animation.StateListAnimator} を XML リソースとして定義する方法を示しています。

<!-- animate the translationZ property of a view when pressed -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true">
    <set>
      <objectAnimator android:propertyName="translationZ"
        android:duration="@android:integer/config_shortAnimTime"
        android:valueTo="2dp"
        android:valueType="floatType"/>
        <!-- you could have other objectAnimator elements
             here for "x" and "y", or other properties -->
    </set>
  </item>
  <item android:state_enabled="true"
    android:state_pressed="false"
    android:state_focused="true">
    <set>
      <objectAnimator android:propertyName="translationZ"
        android:duration="100"
        android:valueTo="0"
        android:valueType="floatType"/>
    </set>
  </item>
</selector>

ビューの状態についてのカスタム アニメーションをビューに付与するには、この例のように XML リソース ファイルの selector 要素を使用して animator を定義し、それを android:stateListAnimator 属性でビューに割り当てます。 コードで StateListAnimator をビューに割り当てるには、{@link android.animation.AnimatorInflater#loadStateListAnimator AnimationInflater.loadStateListAnimator()} メソッドを使用して {@link android.view.View#setStateListAnimator View.setStateListAnimator()} メソッドでビューに animator を割り当てます。

テーマがマテリアル テーマに拡張されると、ボタンにはデフォルトで Z アニメーションが設定されます。これを避けるためには、android:stateListAnimator 属性を @null に設定します。

{@link android.graphics.drawable.AnimatedStateListDrawable} クラスを使用すると、関連するビューの状態遷移にアニメーションを表示するドローアブルを作成できます。 Android 5.0 の一部のシステム ウィジェットでは、デフォルトでこれらのアニメーションを使用しています。 次の例は、{@link android.graphics.drawable.AnimatedStateListDrawable} を XML リソースとして定義する方法を示しています。

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

ベクター型ドローアブルにアニメーションを付ける

ベクター型ドローアブルは定義を失わずにスケールできます。 {@link android.graphics.drawable.AnimatedVectorDrawable} クラスを使うと、ベクター型ドローアブルのプロパティを指定してアニメーションを付けられます。

通常は、次に示す 3 つの XML ファイルで AnimatedVectorDrawable を定義します。

AnimatedVectorDrawable では、<group> 要素と <path> 要素の属性にアニメーションを付けることができます。<group> 要素は一連の経路やサブグループを定義し、<path> 要素は描く経路を定義します。

アニメーションを付けたいベクター型ドローアブルを定義するときは、android:name 属性を使用してグループや経路に一意の名前を割り当てれば animator の定義からそれらを参照できるようになります。 以下に例を示します。

<!-- res/drawable/vectordrawable.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="64dp"
    android:width="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">
    <group
        android:name="rotationGroup"
        android:pivotX="300.0"
        android:pivotY="300.0"
        android:rotation="45.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    </group>
</vector>

AnimatedVectorDrawable の定義では、次のようにベクター型ドローアブルのグループや経路をその名前で参照します。

<!-- res/drawable/animvectordrawable.xml -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@anim/rotation" />
    <target
        android:name="v"
        android:animation="@anim/path_morph" />
</animated-vector>

アニメーションの定義は {@link android.animation.ObjectAnimator} オブジェクトか {@link android.animation.AnimatorSet} オブジェクトを示します。この例の最初の animator は、次のように対象グループを 360 度回転させています。

<!-- res/anim/rotation.xml -->
<objectAnimator
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />

この例の 2 つ目の animator は、ベクター型ドローアブルの経路をある形から別の形へと変化させています。 両方の経路が形の変化に対応できる必要があります。つまり同じ数のコマンドと、各コマンドで同じ数のパラメーターを保持している必要があります。

<!-- res/anim/path_morph.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>

詳細については、API リファレンスの {@link android.graphics.drawable.AnimatedVectorDrawable} をご覧ください。