2011-06-07 yanzm さんが忙しそうなので

_ Android Developers Blog の Introducing ViewPropertyAnimator を訳してみました。

原文は Introducing ViewPropertyAnimatorです。コメントや間違いの指摘は @zaki50 へお願いします。

以前の記事「Animation in Honeycomb」で、Android 3.0 で導入された新しいプロパティアニメーションシステムについてお話しました。この新しいアニメーションシステムは、3.0 でViewクラスに追加された新たなプロパティを含めオブジェクトのあらゆるプロパティを簡単に変化(animate)させることを可能にします。 最近リリースされた 3.1 では、これらの機能をさらに簡単に利用するための小さなユーティリティクラスを追加しています。

始めに、alpha や translationX などの新しく導入された View プロパティについて馴染みがないという方は、以前の記事でこれらを扱っているので "View properties" の節を読んでからここに戻ってきてください。

準備はいいでしょうか?

おさらい: ObjectAnimator の使用

3.0 の ObjectAnimator クラスを使用すると、少量のコードでView プロパティを用いたアニメーションを行うことができます。 Animator を作成し、時間や繰り返しなどのオプションパラメータをセットしてアニメーション開始を指示します。例えば myView オブジェクトをフェードアウトする場合は、アルファプロパティを用いたアニメーションを以下のように行います。

ObjectAnimator.ofFloat(myView, "alpha", 0f).start();

この例を理解するのは難しくないでしょう。 アニメーションの対象オブジェクト, 対象プロパティ, 値を指定して Animator を作成し、実行しています。簡単。

しかし、改善の余地があります。特に、アニメーションに View プロパティを用いるのはよくあることなので、これらのプロパティを用いるアニメーションに対して出来る限り簡単で可読性のよい API を提供できるのではないでしょうか。また、これらのプロパティを用いたアニメーションのパフォーマンス面での改善も行いたいと考えました。この最後のポイントについては次のパラグラフで説明します。

View プロパティを用いた 3.0 のアニメーションモデルには、改善すべき3つの点があります。1つは、"プロパティ"という概念をもたないプログラミング言語上でプロパティによるアニメーションを行うという仕組みに関するものです。残る問題は、複数のプロパティを用いたアニメーションに関するものです。View をフェードアウトするのであれば、 alpha プロパティに対してアニメーションを適用するだけです。しかし、スクリーン上を移動させようとすると、x と y (または translationX と translationY) プロパティを並行して変化させる必要があります。このほかにも、Viewプロパティに対するアニメーションを並行して適用する必要がある状況はたくさん存在します。複数のプロパティに対するアニメーションが並行して行われることが予めわかってるのであれば、アニメーションごとに発生するある種のオーバーヘッドについてはひとまとめにすることが可能です。

Android のランタイムは "プロパティ"という概念を持っていないので、 ObjectAnimator はプロパティ名を表す文字列を対象オブジェクトに対するセッターの呼び出しへ変換するテクニックを用います。例えば、"alpah"という文字列は View の setAlpha() を指すように変換されます。このメソッドはリフレクションや JNIを通して呼び出されますが、これには呼び出しに対するオーバーヘッドが存在します。View のプロパティのように既知のプロパティに対してはもっと良い方法で操作できるべきです。少々の API とアニメーションに使用するプロパティに関する知識があれば、リフレクションや JNIのオーバーヘッドなしに直接オブジェクトに値をセットすることができるはずです。

オーバーヘッドは Animator 自身にも存在します。ほとんど全てのアニメーションは1つの同期機構を共有しているのでタイミングイベントのオーバーヘッドは重複しませんが、それぞれのプロパティに対するタスクは別々のオブジェクトです。もしこれらのタスクが1つのアニメーションでの複数プロパティ操作であることが事前に分かっていれば、これらを1つに結合することができます。既存のシステムでこれを行う1つの方法は PropertyValuesHolder です。このクラスは、1つのオブジェクトの複数プロパティに対するアニメーションを行う Animator オブジェクトを提供するので、個々の Animator 毎に発生するオーバーヘッドの大部分を省くことができます。しかしこのアプローチは、本質的にはシンプルな操作に対しても多くのコードと複雑性を持ち込んでしまいます。新たなアプローチでは、1つのアニメーションに属する様々なプロパティの操作をよりシンプルな方法で結合することを可能にします。

最後に、View のプロパティそれぞれが、オブジェクトとその親に対する適切な invalidation を保証するために様々な処理を実行します。例えば View の x 座標の遷移は、親が適切に再描画を行えるようにするために View の元の位置と移動先の位置それぞれの領域を invalidate します。同時に、y 座標の遷移もビューの元の位置、移動先の位置それぞれで invalidate を行います。もしこれらのアニメーションが同時に実行された場合、本来であれば省略可能であったはずの invalidation 処理が発生します。 ViewPropertyAnimator はこの点をケアします。

導入: ViewPropertyAnimator

ViewPropertyAnimator は内部に保持する1つのAnimator オブジェクトを使って、複数のプロパティに対するアニメーションを並行しで実行することを可能にします。また、複数のプロパティの値を計算するので、対象とする View に直接値をセットし適切にオブジェクトを invalidate します。これは ObjectAnimator が行うよりも効果的な方法です。

説明はこのくらいにして: コードに移りましょう。先ほど取り上げたビューをフェードアウトする例に対して、ViewPropertyAnimator を使って以下のように書くことができます。

myView.animate().alpha(0);

いいね! 短いし可読性も高い。それに他のプロパティアニメーションを追加するのも簡単です。例えば、ビューの (x, y) を (500, 500) に移動させるのは以下のような感じでできます。

myView.animate().x(500).y(500);

これらのコマンドについて注目すべきいくつかのポイントがあります:

  • animate(): システムの魔法は View に新たに追加された animate() メソッドを呼ぶことから始まります。このメソッドは ViewPropertyAnimator のインスタンスを返します。このインスタンスはアニメーションプロパティをセットするためのメソッド群を提供します。
  • Auto-start: アニメーションの実行のために start() を呼び出していないことに注目してください。新たに追加された API では、アニメーションを明示的に実行する必要はなく、宣言が完了するとすぐに実行が開始されます。Together. 正確には、アニメーションは UI ツールキットイベントキューからの次回のアップデートまで実行を待機しています。これがViewPortAnimator がすべてのアニメーション宣言を集めてから実行することを可能にするメカニズムです。アニメーションを宣言し続ける限り、次のフレームで実行されるアニメーションのためのリストに追加され続けます。UIスレッドでの処理が終わるとすぐに、イベントキューメカニズムがアニメーションを開始させます。
  • Fluent: ViewPropertyAnimator はとても自然な方法でメソッド呼び出しを連鎖可能にする流れるようなインタフェースを提供するため、複数プロパティに対するアニメーションを単一行のコードとして発行することができます。つまり、 x() や y() のようなすべてのメソッド呼び出しは ViewPropertyAnimator インスタンスを返します。このインスタンスに対して、他のメソッドの呼び出しを連鎖させます。先程の例からも、コードはとてもシンプルで可読性が高いことがわかると思います。しかし、 ViewPropertyAnimator のパフォーマンスの改善はどこからやってくるのでしょうか。

パフォーマンスの懸念

新しいアプローチがパフォーマンス上有利な点のひとつはアルファ値によるアニメーションというこのシンプルな例でも見て取れます。 ViewPropertyAnimator はリフレクションや JNI を使用していません。例えば、前述の例で用いた alpha() メソッドは View の "alpha" フィールドを直接操作します。この操作はフレーム毎に1回行われます。

ViewPropertyAnimator のもうひとつのパフォーマンス上の利点は、複数のアニメーションを結合する能力に由来します。もうひとつの例を見てみましょう。

ビューをスクリーン上で動かす際、オブジェクトの x 座標と y 座標の両方を変化させるかもしれません。 例えば、以下のアニメーション処理は myView の x,y を 50,100 に変化させます。

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

上記のコードは2つの別々のアニメーションを作成し、 AnimationSet を用いてひとまとめに実行します。 これは AnimationSet を用意するための処理のオーバーヘッドとx,y の値を変化させるために2つの Animator を並行して実行するためのオーバーヘッドが存在することを意味します。 別のアプローチとして、複数のプロパティを1つの Animator の中で変化させるために PropertyValueHolder を用いる方法もあります。

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("y", 50f); // zaki memo: 100f の間違いでは?
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

この方法では複数の Animator によるオーバーヘッドを避けることができ、ViewPropertyAnimator 以前の実現方法としては正しいです。 しかしコードはいまいちです。 ViewPropertyAnimator を使えば、もっと簡単に実現できます。

myView.animate().x(50f).y(100f);

これならコードはよりシンプルで可読性も高いです。加えてViewPropertyAnimator は内部に保持する1つの Animator によってすべてのプロパティに対する処理が実行されるため、前述の PropertyValuesHolder の方法と同じく複数の Animator を使用しないというアドバンテージも持っています。

しかし、前出の ViewPropertyAnimator の例にはコードには現れないもうひとつの利点があります。この方法はそれぞれのプロパティに値をセットする際の内部的な処理を省略できます。通常、View の setX() と setY() が呼ばれた場合、view の移動に伴って適切な領域が再描画されることを保証するために ある程度の計算と invalidation が行われます。 ViewPropertyAnimator はこれらの計算を プロパティごとではなくフレーム毎に1回だけ実行します。View の x,y に直接値をセットし、x, y(及びアニメーションに関連するすべてのプロパティ) に対して invalidation の計算を一度だけ行うことで ObjectAnimator での方法では避けることが出来なかったプロパティ毎のオーバーヘッドを回避します。

記事を終わるにあったって今まで見てきたように... というのは退屈です! 視覚効果についてお話した事を実際にお見せしたいと思います。難しいのはアニメーションの話をする際にはスクリーンショットというものが一切役に立たないという点です。("この画像でボタンが動いているのがわかると思います。はい、今は動いてませんが、スクリーンショットを撮った際には動いていました。本当です!") そこで、私が作成した小さなデモアプリケーションのビデオを撮影したので、プログラムのコードを追っていきたいと思います。

ビデオをご覧ください。開始する前にスピーカーがオンになっていることを確認するように。オーディオが醍醐味ですから。

ビデオでは、左上の("Fade In", "Fade Out" などの)ボタンがクリックされると、一番下のボタン("Animating Button")にエフェクトがかかるのがわかると思います。 これらすべてのアニメーションは (もちろん) ViewPropertyAnimator API によるものです。以下に、それぞれのエフェクトを実現するコードに付いてみていきます。

アクティビティが開始されると、デフォルトよりも長い時間をかけてアニメーションが実行されるようにセットアップされます。これはビデオで確認するのに十分な時間アニメーションが実行されてほしいからです。animatingButton オブジェクトのデフォルト持続時間を変更するのは、 ボタンの ViewPropertyAnimator を取得して時間をセットする1行の処理で表せます。

animatingButton.animate().setDuration(2000);

その他のコードは、ボタンが押された際に対応するアニメーションが開始されるよう OnClickListener オブジェクトをボタンにセットするためのものです。1つ目のアニメーションについてはリスナー全体を記述しますが、2つ目以降はリスナーのお約束部分は省略してメソッド内のコードだけ記述します。

ビデオでの最初のアニメーションは Fade Out ボタンがクリックされると発動し、Animation Button がフェードアウトしていきます。 Fade Out ボタンが実行しているリスナを示します。

fadeOut.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        animatingButton.animate().alpha(0);
    }
});

コードを見ればわかるように、単にオブジェクトに対してalpha が 0 になるようにアニメーションすることを伝えています。 常に現在の alpha 値からアニメーションが開始されます。

次のボタンはフェードイン、つまりボタンの alpha を 1(不透明) に戻します。

animatingButton.animate().alpha(1);

Mode Over と Move Back ボタンは2つのプロパティ x と y を並行して変化させます。 これはそれぞれのプロパティをアニメーションさせるメソッドチェインさせることで実現しています。Move Over ボタンに対するコードは以下のとおりです。

int xValue = container.getWidth() - animatingButton.getWidth();
int yValue = container.getHeight() - animatingButton.getHeight();
animatingButton.animate().x(xValue).y(yValue);

Move Back のケース(コンテナの元の位置(0, 0)に戻す)に対しては、以下のコードです。

animatingButton.animate().x(0).y(0);

ビデオの中で注目して欲しいのは、Move Over や Move Back を実行中に再度アニメーションを走らせていること、言い換えるとMove Over のアニメーションの実行中に Move Back をクリックしている点です。同一のプロパティ(x や y)に対する2つ目のアニメーションは1つ目のアニメーションをキャンセルし、現在の場所から2つ目のアニメーションを開始します。これは ViewPropertyAnimator の意図的な機能の1つです。プロパティに対するアニメーションコマンドを受け取り、必要であれば現在実行中のアニメーションをキャンセルします。

最後に、ボタンが Y軸の周りを2回転する3D回転エフェクトです。これは明らかに複雑なアクションで、他のアニメーションよりもはるかに大量のコードが必要と思いませんか?

animatingButton.animate().rotationYBy(720);

ビデオでの回転アニメーションで注目すべき重要な点の1つは、移動のアニメーションと並行して動いているということです。 Move Over ボタンをクリックしてから Rotate ボタンを押すところです。最初の操作によって移動が始まり、次の操作で移動が行われたまま回転が開始されます。それぞれのアニメーションは2秒間続くので、移動のアニメーションが終わったあとで回転のアニメーションが完了します。ボタンが元に戻る際も同様で、ボタンが元の位置(0, 0) に着いた後も回転は続いています。これは、独立したアニメーション(1つのアニメーターにグルーピングされないアニメーション)に対しては、独立かつ並行してアニメーションが行われるようにするため内部的には別々の ObjectAnimator が作成されることを示しています。

デモで遊び、コードをチェックアウトし、16.75 の素晴らしいサウンドトラックを楽しんでください。そして、この(前述の5つのアニメーターコードを内包した OnClickリスナーのみで構成されている)恐ろしく複雑なアプリケーションのソースコードが欲しいのであれば、 ここからダウンロード できます。

And so...

ViewPropertyAnimator の完全な説明として、SDK ドキュメントを見ようと思うかもしれません。 1つ目は View の animate() メソッドです。2つ目は、 ViewPropertyAnimator クラス自身です。 ViewPropertyAnimator クラスの基本的な機能についてはこの記事でカバーしましたが、今回とりあげなかったアニメーション関連のメソッドがまだいくつかあります。3つ目は...ありません。View クラスと ViewPropertyAnimator クラスが全てです。

ViewPropertyAnimator は 3.0 で追加されたプロパティアニメーションの API に対する置き換えを意味するのではありません。 単なる追加です! 実際、3.0 で追加されたアニメーションの能力は ViewPropertyAnimator やシステムの他のアニメーション機能に対して重要なインフラを提供しています。 そして、 ViewPropertyAnimator の能力はアニメーションを行うにあたってとても柔軟で使いやすいファシリティを提供してくれます。 しかし、View の標準的なプロパティの一つに簡単にアニメーションを行いたい場合で、より制限された形の ViewPrpertyAnimator API があなたの要求に適しているのであれば、それは考慮に値します。

注: ObjectAnimator のオーバーヘッドについて過度に心配させたいのではありません。リフレクション, JNI, その他アニメーターの処理のオーバーヘッドはプログラムの他の部分で行っている処理に比べればはるかに小さいです。 ViewPropertyAnimator の効果は、大量の View プロパティアニメーションを行う際に特に発揮されます。しかし私には、新たな API の最も良い部分はあなたが書くコードです。簡潔で高い可読性を実現するのが最も良い API です。 あなたがこれに同意し、ビュープロパティアニメーションが必要となった際に ViewPropertyAnimator を使ってくれることを願います。

_ New Editing Features in Eclipse plug-in for Androidを訳してみた。

原文はNew Editing Features in Eclipse plug-in for Androidです。コメントや間違いの指摘は @zaki50 までお願いします。

Posted by Xavier Ducrohet, Android SDK Tech Lead on 06 June 2011 at 4:30 PM

先月の Google I/O で、Android Development Tools(ADT) プラグインの次バージョンを披露しました。今日は、バージョン11 のダウンロード開始をアナウンスできることを嬉しく思います。

ADT 11 はエディターの改善にフォーカスします。 1つ目はビジュアルリファクタリング操作です。 これは"include抽出(Extract Include)" や"スタイル抽出(Extract Style)" と呼ばれ、重複するレイアウトの断片やスタイルを再利用可能なレイアウト、スタイル、テーマとして自動的に抽出します。

2つ目は、ビジュアルレイアウトエディタのフラグメントサポート、パレット設定せポート、改善されたカスタムビューサポートです。

最後は、XML の編集が改善されたことです。具体的にはクイックフィックス、より多くのファイルタイプにおけるコード補完、たくさんの "宣言を開く(go to declaration)" の拡張です。

ADT 11 にはたくさんの新機能と拡張が含まれています。詳細は ADTページ を見てください。詳しいデモは、次のGoogle I/O の Android Development Toolsセッションのビデオを見てください。

ビジュアルレイアウトエディターはSDK内のそれぞれのバージョンのプラットフォームコンポーネントに含まれるレイアウトレンダリングライブラリに依存していることに注意してください。このライブラリに対しても現在たくさんの改良を進めている最中で、近いうちにすべてのプラットフォームバージョンに対してリリースを計画しています。ListView プレビューサポートなど、ADT 11 に含まれるいくつかの新機能はライブラリのリリースの際に有効になります。このブログでのアナウンスに注目していてください。


«前の日記(2010-12-24) 最新