Androidの最近のブログ記事

ActionScript 用の有名なアニメーションライブラリである Tweener を Android で使用する方法について説明します。

 

Tweener を使用すると、

Tweener.to(imageView, 3000, "alpha", 0);

のような感じでプロパティアニメーションさせたり、

 

Tweener.to(imageView, // アニメーション対象
    3000, // アニメーション期間(単位はミリ秒)
    "translationX", 200.0f, // 変化させたいプロパティ名, 値
    "translationY", 100.0f, // 変化させたいプロパティ名, 値
    "ease", Ease.Quad.easeInOut, // 補間関数
    "onComplete", new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            // 必要であれば、アニメーション終了時のコードを書きます
        }
    });

のような感じで、複雑なアニメーション(複数プロパティ、補完関数変更、終了イベント補足)も、短いコードで書くこともできます。

 

Android 3.0 以降であれば、Android でもプロパティアニメーションがサポートされているため、

新たに Tweener を使用するまでもないのですが、Tweener の方が馴染みがある場合には、役に立つかもしれません。

ちなみにプロパティアニメーションについては『Androidプログラミング上達読本』にも解説があるので、興味を持った方は読んでみてください^^;

 

使い方

1. AOSP から Android 4.0 以降のソースコードをダウンロードする。

 ※必要なコードは frameworks 下の一部のコードだけなので repo ではなく、git で直接取得してもよいです

git clone https://android.googlesource.com/platform/frameworks/base

 

2. 取得したコードの中から以下のクラスをコピーし、任意のパッケージ名に変更する。

  • frameworks\base\core\java\com\android\internal\widget\multiwaveview\Tweener.java
  • frameworks\base\core\java\com\android\internal\widget\multiwaveview\Ease.java

 ※Tweener クラスはパッケージスコープになっているので必要に応じてアクセスレベルを変更してください

 ※パッケージ名を変更しないと、4.0(ICS)―4.1(JB)間で内部クラスが変更されているので上手く動作しない可能性があります

 

3. Tweener.to() を呼び出し、Tweener アニメーションコードを書く。

 ※変化させるプロパティ名は、ActionScript でなく、Adnroid で使用できるプロパティ名を書きます

 ※Tweener.from() などは移植されていないようです

 

Tweener

  • tweener - A class for creating tweens in actionscript 2 and 3 - because there's infinity between 0 and 1. - Google Project Hosting

ActionScript は言語レベルでプロパティをサポートされているので、Tweener の実装は非常にシンプルなコードになっています。

 

Android 4.0 フレームワークの内部クラスで実装されている Tweener のコード

  • Twneer.java

Android のプロパティアニメーションAPI(PropertyValuesHolder、ObjectAnimator など)を使用して移植されています。

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.widget.multiwaveview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import android.animation.Animator.AnimatorListener;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.util.Log;
class Tweener {
    private static final String TAG = "Tweener";
    private static final boolean DEBUG = false;
    ObjectAnimator animator;
    private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
    public Tweener(ObjectAnimator anim) {
        animator = anim;
    }
    private static void remove(Animator animator) {
        Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<Object, Tweener> entry = iter.next();
            if (entry.getValue().animator == animator) {
                if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
                        + " sTweens.size() = " + sTweens.size());
                iter.remove();
                break; // an animator can only be attached to one object
            }
        }
    }
    public static Tweener to(Object object, long duration, Object... vars) {
        long delay = 0;
        AnimatorUpdateListener updateListener = null;
        AnimatorListener listener = null;
        TimeInterpolator interpolator = null;
        // Iterate through arguments and discover properties to animate
        ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
        for (int i = 0; i < vars.length; i+=2) {
            if (!(vars[i] instanceof String)) {
                throw new IllegalArgumentException("Key must be a string: " + vars[i]);
            }
            String key = (String) vars[i];
            Object value = vars[i+1];
            if ("simultaneousTween".equals(key)) {
                // TODO
            } else if ("ease".equals(key)) {
                interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
            } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
                updateListener = (AnimatorUpdateListener) value;
            } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
                listener = (AnimatorListener) value;
            } else if ("delay".equals(key)) {
                delay = ((Number) value).longValue();
            } else if ("syncWith".equals(key)) {
                // TODO
            } else if (value instanceof float[]) {
                props.add(PropertyValuesHolder.ofFloat(key,
                        ((float[])value)[0], ((float[])value)[1]));
            } else if (value instanceof Number) {
                float floatValue = ((Number)value).floatValue();
                props.add(PropertyValuesHolder.ofFloat(key, floatValue));
            } else {
                throw new IllegalArgumentException(
                        "Bad argument for key \"" + key + "\" with value " + value.getClass());
            }
        }
        // Re-use existing tween, if present
        Tweener tween = sTweens.get(object);
        ObjectAnimator anim = null;
        if (tween == null) {
            anim = ObjectAnimator.ofPropertyValuesHolder(object,
                    props.toArray(new PropertyValuesHolder[props.size()]));
            tween = new Tweener(anim);
            sTweens.put(object, tween);
            if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
        } else {
            anim = sTweens.get(object).animator;
            replace(props, object); // Cancel all animators for given object
        }
        if (interpolator != null) {
            anim.setInterpolator(interpolator);
        }
        // Update animation with properties discovered in loop above
        anim.setStartDelay(delay);
        anim.setDuration(duration);
        if (updateListener != null) {
            anim.removeAllUpdateListeners(); // There should be only one
            anim.addUpdateListener(updateListener);
        }
        if (listener != null) {
            anim.removeAllListeners(); // There should be only one.
            anim.addListener(listener);
        }
        anim.addListener(mCleanupListener);
        anim.start();
        return tween;
    }
    Tweener from(Object object, long duration, Object... vars) {
        // TODO:  for v of vars
        //            toVars[v] = object[v]
        //            object[v] = vars[v]
        return Tweener.to(object, duration, vars);
    }
    // Listener to watch for completed animations and remove them.
    private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            remove(animation);
        }
        @Override
        public void onAnimationCancel(Animator animation) {
            remove(animation);
        }
    };
    public static void reset() {
        if (DEBUG) {
            Log.v(TAG, "Reset()");
            if (sTweens.size() > 0) {
                Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
            }
        }
        sTweens.clear();
    }
    private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
        for (final Object killobject : args) {
            Tweener tween = sTweens.get(killobject);
            if (tween != null) {
                tween.animator.cancel();
                if (props != null) {
                    tween.animator.setValues(
                            props.toArray(new PropertyValuesHolder[props.size()]));
                } else {
                    sTweens.remove(tween);
                }
            }
        }
    }
}

 

  • Ease.java

Tweener で定義されているイージングを Android のプロパティアニメーションAPI を使用して移植してあります。

TimeInterpolator を継承したクラスなので、ここだけでも使えますね!

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.widget.multiwaveview;
import android.animation.TimeInterpolator;
class Ease {
    private static final float DOMAIN = 1.0f;
    private static final float DURATION = 1.0f;
    private static final float START = 0.0f;
    static class Linear {
        public static final TimeInterpolator easeNone = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return input;
            }
        };
    }
    static class Cubic {
        public static final TimeInterpolator easeIn = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN*(input/=DURATION)*input*input + START;
            }
        };
        public static final TimeInterpolator easeOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START;
            }
        };
        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return ((input/=DURATION/2) < 1.0f) ?
                        (DOMAIN/2*input*input*input + START)
                            : (DOMAIN/2*((input-=2)*input*input + 2) + START);
            }
        };
    }
    static class Quad {
        public static final TimeInterpolator easeIn = new TimeInterpolator() {
            public float getInterpolation (float input) {
                return DOMAIN*(input/=DURATION)*input + START;
            }
        };
        public static final TimeInterpolator easeOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return -DOMAIN *(input/=DURATION)*(input-2) + START;
            }
        };
        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return ((input/=DURATION/2) < 1) ?
                        (DOMAIN/2*input*input + START)
                            : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START);
            }
        };
    }
    static class Quart {
        public static final TimeInterpolator easeIn = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN*(input/=DURATION)*input*input*input + START;
            }
        };
        public static final TimeInterpolator easeOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START;
            }
        };
        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return ((input/=DURATION/2) < 1) ?
                        (DOMAIN/2*input*input*input*input + START)
                            : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START);
            }
        };
    }
    static class Quint {
        public static final TimeInterpolator easeIn = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN*(input/=DURATION)*input*input*input*input + START;
            }
        };
        public static final TimeInterpolator easeOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START;
            }
        };
        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return ((input/=DURATION/2) < 1) ?
                        (DOMAIN/2*input*input*input*input*input + START)
                            : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START);
            }
        };
    }
    static class Sine {
        public static final TimeInterpolator easeIn = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START;
            }
        };
        public static final TimeInterpolator easeOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START;
            }
        };
        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
            public float getInterpolation(float input) {
                return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START;
            }
        };
    }
}

 

あわせて読みたい

android1.6_2.png android1.6.png  

Android 3.0 以降で追加されたプロパティアニメーション機能の一部(ここ重要)をバックポートしたライブラリを作成しました。

 

このライブラリを使用すると、なんと! Android 1.6 環境でも、

独自に作成したオブジェクトのカスタムプロパティ(※)に限られますが、プロパティアニメーションをさせることができます。

(※Android 3.0 以降にしか存在しない View の組み込みプロパティ(x, y, alpha...など)は使用できない)

 

冒頭の画面キャプチャは、あの HT-03A(Android 1.6)上で Android 4.0 の API Demos に含まれる

プロパティアニメーションのサンプルが動作している様子です。

HT-03A(Android 1.6)たん可愛いよ。

IS01(Android 1.6)たん可愛いよ。

 

ソースコード

※Android 4.0 の API Demos のプロパティアニメーションのコードのうち、
 Android 1.6 + 本ライブラリで使用できる 6 つのサンプルコードも収録しています。

 

サポートしているクラス(制限事項あり)

  • Animator
  • AnimatorListenerAdapter
  • AnimatorSet
  • ArgbEvaluator
  • FloatEvaluator
  • FloatKeyframeSet
  • IntEvaluator
  • IntKeyframeSet
  • Keyframe
  • KeyframeSet
  • ObjectAnimator
  • PropertyValuesHolder
  • TimeAnimator
  • TypeEvaluator
  • ValueAnimator

※制限事項

変化させる対象のプロパティは独自に定義したものに限られます。
例えば、View の移動、回転、拡大縮小、アルファなどの組み込みプロパティは、
Android 3.0 以降のフレームワークに組み込まれているプロパティのため使用できません><

 

非サポートクラス

  • AnimatorInflater → リソースに定義したアニメーションからのインフレート
  • LayoutTransition → レイアウト変更時に適用するアニメーション
  • TimeInterpolator → 従来の android.view.Interpolator
  • ViewPropertyAnimator → View の組み込みプロパティに対する最適化されたアニメーション

 

バックポート手順

詳細なバックポート手順については下記リンク先(Google Drive(ログイン不要))に上げました。

https://docs.google.com/document/d/1fu9p3hfG8GDJOg6H6rIuWhhiGhsAQ4msMPb_pSiRI8g/edit

Google Code 内のリポジトリのコミットログにも細かくコメントをつけてますので、そちらを参照してもわかるかと思います。

コードを読むと、言語レベルでプロパティをサポートしていない Android において、

いかにしてプロパティを実現しているか理解できて面白いと思います。

一部、NDKを使用してネイティブコードも使用しています。

 

Androidプログラミング上達読本

あっ、そうそう、大事なこと言い忘れてました。

このたび、リックテレコムさんから出版される「Androidプログラミング上達読本」の Section 4 の執筆を担当しました。

同 Section にてプロパティアニメーションの API を解説していますので、あわせて読んでいただければ有難いです。

この本は、他にも、タオガクさんや、やんざむさんなど著名な方々の記事で構成されています。

2012年8月4日 ~10日 くらいには発売されますので、見かけた際には、是非手に取って確認してみてください。

book902.png

http://www.ric.co.jp/book/contents/book_902.html

 

私が書いた記事の構成としては、4-2  で API の解説をしていますが、

どちらかというと、4-2 は、困ったときに逆引き的な読めるように書いた/レイアウトしたので、

時間のない方は、プロパティアニメーションの魅力を理解するために

4-3、4-4 を斜め読みするのが良いかもしれません。

また、4-3 では、あの伝説の、、、「第4回 SHARPハッカソン」で生まれたスタ★ミやモグタソも登場します。

最後の 4-4 は、グラフ(カスタムビューのカスタムプロパティ)のアニメーションで、

Android 3.0 以降向けに作成したものですが、本エントリのバックポートライブラリを使用すると、

なんと Android 1.6 でも動作してしまいますー。

ちなみに、Google Drive に上げたバックポート手順は、紙面の都合上カットした没記事です^^;

30ページの枠ですが、勢い余って50ページ書いてました。。。

ということで、本エントリ以外にも、まだ隠し玉があったりします///

 

個人的には、プロパティアニメーションを使用したアプリが増えてくるのは・・・

2013年以降かな。。。

と思ってますので、末永く手元に置いていただければ・・・と思います^^;

 

あわせて読みたい

customLogo.png 

2012年7月8日、東京・京都・名古屋・中国・四国・九州・信州・米国 で同時開催された

DevFestX Japan 2012 Summer に参加してきました。

 

公式サイト

 

講演スライド(直リンク)

 

各会場からアップされた画像

最近 Google+ に追加された「イベント」機能のパーティーモードを使った写真

 

Togetter

@roishi2j2 さんによるまとめ

@tamacjp さんによるまとめ

 

お土産

「android ロボットのUSBメモリ」 や 「Google のビーチサンダル」 を頂きました。

usb.jpg

 

信州会場

Google Maps API Expert の 石丸(@kehi)さん、古籏(@openspc)さんの働きかけにより、

信州会場(パブリックビューイング)として開催していただけました。

「GTUG がない → DevFestX 行けない → しょぼーん(´・ω・`) 」 ではなく、

「ないなら創る → DevFestX やる → イヤッホゥ(゜∀゜)!!」 という流れです。

 

パブリックビューイングということでしたが、実際には他の会場と同様に Google+ Hangout で接続され、

地方にいながら、皆さんと同じ体験をすることができました。これも、

当日ぎりぎりまで準備してくださった Google Expert の方々、素晴らしい会場を提供してくださった S.I.P の方々、

裏方で運営をサポートしてくださった方々、満席になるほど参加して盛り上げてくださった皆様のおかげですね。

大変有難いことですm_ _m

 

@lychee さんのツイートにもありましたが、まさにそのとおりだと感じました。

221873380897460224.png

 

まとめると・・・

 

221834100988846080.png

 

九州会場凄い!ハングアウト凄い!

Android 4.1 (API Level 16)の ViewPropertyAnimator の変更点を調べました。

 

変更点

以下の3メソッドが追加されています。

  • withLayer()
  • withStartAction(Runnable)
  • withEndAction(Runnable)

 

解説

  • withLayer()

ViewPropertyAnimator を使用してアニメーションを実行する時、

アニメーション対象の View をハードウェアレイヤを使用してアニメーションさせます。

アニメーション終了後は、この設定はクリアされます。

ただし、ハードウェアアクセラレータが使用できない環境では、ソフトウェアレイヤが使用されます。

レイヤーの合成処理をハードウェアに任せることで高速化が期待できます。

 

  • withStartAction(Runnable) / withEndAction(Runnable)

ViewPropertyAnimator を使用したアニメーションの開始/終了時に実行したい処理を設定できます。

 

追加されたメソッドについて、実際に呼び出してみました。

以下のコードを実行すると、アニメーション開始時(3秒後)に、withStartAction() で指定した処理、

アニメーション終了時に、withEndAction() で指定した処理が呼び出されます。

また、withLayer() を呼び出しているので、ビュー(ここではボタン)のアニメーションは、ハードウェアレイヤ上で処理されます。

 

サンプルソースコード

final Button button = (Button) findViewById(R.id.button);
// 指定した View から ViewPropertyAnimator インスタンスを取得する
ViewPropertyAnimator vpa = button.animate();
// ハードウェアアクセラレータが使用できる環境では、ハードウェアレイヤを使用するように設定
vpa.withLayer();
// アニメーション継続期間を設定する(ミリ秒)
vpa.setDuration(3000);
// アニメーション開始時に実行する処理を設定する
vpa.withStartAction(new Runnable() {
    @Override
    public void run() {
        // アニメーション開始時に呼び出されます。
        // アニメーション開始遅延時間が設定されている場合は、
        // アニメーション開始遅延時間後に呼び出されます。
        String layerTypeString = "";
        int layerType = button.getLayerType();
        switch (layerType) {
            case View.LAYER_TYPE_NONE:
                // withLayer() を呼び出さなかった時
                layerTypeString = "LAYER_TYPE_NONE";
                break;
            case View.LAYER_TYPE_SOFTWARE:
                // withLayer() を呼出した時、
                // ハードウェアアクセラレータが使用できない環境では、ソフトウェアレイヤを使用される
                layerTypeString = "LAYER_TYPE_SOFTWARE";
                break;
            case View.LAYER_TYPE_HARDWARE:
                // withLayer() を呼出した時、
                // ハードウェアアクセラレータが使用できる環境では、ハードウェアレイヤを使用される
                layerTypeString = "LAYER_TYPE_HARDWARE";
                break;
        }
        Log.v("ViewPropertyAnimatorSample",
                "withStartAction() using " + layerTypeString);
    }
});
// アニメーション終了時に実行する処理を設定する
vpa.withEndAction(new Runnable() {
    @Override
    public void run() {
        // アニメーション修了時に呼び出されます。
        Log.v("ViewPropertyAnimatorSample", "withEndAction()");
        button.setVisibility(View.GONE);
    }
});
// ビューに対してアニメーションを設定する(-> アニメーションが開始されます)
vpa.rotation(90);

 

Android SDK Tools, Revision 20 から、システムワイドなトレースツールである systrace が追加されました。

このツールを使うと、ユーザランドとカーネルの詳細なトレース結果を得ることができるので、パフォーマンス解析に役立ちます。

 

準備

  • PC に「Android SDK Tools, Revision 20」をインストールする。
  • PC に Python (実行環境)をインストールする。
  • Android 4.1 端末を PC と接続する。
  • 端末上の設定アプリで「開発者オプション」 > 「トレースを有効にする」 で任意の有効なトレースを選択する。

 

systrace の使い方

android-sdk/tools/systrace ディレクトリに移動し、systrace.py を実行する(※)。

※実行するには「python systrace.py」、または、実行権(x)を付加して「./systrace.py」

デフォルトでは 5 秒間トレースされますが、-t でトレース時間(単位は秒)を指定できます。

systrace1.png

 

実行結果

実行すると、trace.html ファイルが生成されるので、Chrome ブラウザ(※)で開きます。

※Firefox では正常に動作しませんでした

 

下図は、「API Demos」 > 「Graphics」 > 「OpenGL ES」 > 「Sprite Text」 を 1 秒間トレースした結果です。

trace.html ファイルは、HTML + Javascript で操作できるようになっていて、

色のついているエリアをダブルクリックすると、拡大できたり、範囲選択すると、下側に詳細な説明が表示されます。

VSYNC 美しいです!

VSYNC 美しいです!

trace.png

 

おまけ

systrace の出力結果には、trace-viewer という Chrome の Javascript ベースなトレースツールを使っているようです。

  • trace-viewer - Javascript-based trace visualization - Google Project Hosting

trace-viewer is the javascript frontend for Chrome's about:tracing UI, and can be used to visualize and analyze traces from various tracing libraries, including the linux kernel and Chrome's base/trace_event system.

また、systrace ツール自体は、python スクリプトで記述されていて、内部的には、adb shell から  atrace を実行しているようです。

 

あわせて読みたい

Android 4.1(Jelly Bean) から Activiy 起動アニメーションが簡単に指定できるようになりました。

 

Activity 起動アニメーション種類

  • スケールアップ(ScaleUpAnimation)
  • サムネイルスケールアップ(ThumbnailScaleUpAnimation)
  • カスタムアニメーション(CustomAnimation)

 

使い方

  1. ActivityOptions クラスの静的メソッド(makeXXX)を呼び出して同クラスをインスタンス化する。
  2. インスタンス化した ActivityOptions を、startActivity の引数に渡す。

 

以下、それぞれのアニメーションの解説です。

 

スケールアップ(ScaleUpAnimation)

画面上の指定された開始位置から、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// アニメーションの基点となるビュー
Button view = (Button) findViewById(R.id.button);
// スケールアップ用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(
    view,
    0, 0, view.getWidth(), view.getHeight());
// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());

 

サムネイルスケールアップ(ThumbnailScaleUpAnimation)

指定したサムネイル(Bitmap)を指定した位置から、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// アニメーションの基点となるビュー
Button view = (Button) findViewById(R.id.button);
// ここではサンプルとしてスケールアップするアニメーションの画像に
// ボタンの画像(Bitmap)を使用していますが、任意の画像を使用することができます。
view.setDrawingCacheEnabled(true); // 後で元に戻すこと
view.setPressed(false);
view.refreshDrawableState();
Bitmap bitmap = view.getDrawingCache();
// サムネイルスケールアップ用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
    view,
    bitmap, 0, 0);
// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());
view.setDrawingCacheEnabled(false);

 

カスタムアニメーション(CustomAnimation)

カスタムアニメーション(リソース)を指定して、新しいアクティビティを拡大するアニメーション。

 

  • ソースコード
// カスタムアニメーション用 ActivityOptions をインスタンス化
ActivityOptions opts = ActivityOptions.makeCustomAnimation(
    MainActivity.this,
    R.anim.zoom_enter, R.anim.zoom_exit);
// アニメーションを指定してアクティビティを起動
startActivity(
    new Intent(this, SecondActivity.class),
    opts.toBundle());

 

  • カスタムアニメーションリソース(サンプル)・・・R.anim.zoom_enter
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/decelerate_interpolator" >
    <scale
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromXScale="2.0"
        android:fromYScale="2.0"
        android:pivotX="50%p"
        android:pivotY="50%p"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>

 

  • カスタムアニメーションリソース(サンプル)・・・R.anim.zoom_exit
    • <set xmlns:android="http://schemas.android.com/apk/res/android"
          android:interpolator="@android:anim/decelerate_interpolator"
          android:zAdjustment="top" >
          <scale
              android:duration="@android:integer/config_mediumAnimTime"
              android:fromXScale="1.0"
              android:fromYScale="1.0"
              android:pivotX="50%p"
              android:pivotY="50%p"
              android:toXScale=".5"
              android:toYScale=".5" />
          <alpha
              android:duration="@android:integer/config_mediumAnimTime"
              android:fromAlpha="1.0"
              android:toAlpha="0" />
      </set>
      

       

      あわせて読みたい

      Android 4.1(Jelly Bean) から新しく 3 つのスタイルが使用できるようになりました。

      • BigTextStyle
      • BigPictureStyle
      • InboxStyle

      また、通知領域に簡単にボタンを追加できるようにもなっています。

       

      以下、それぞれの画面キャプチャとソースコードです。

      画面キャプチャと、ソースコード中の文字列を比較しながら見ると、わかりやすいと思います^^

       

      Notification.BigTextStyle

      BigTextStyle は「テキスト(Summary Text)」と「小さいアイコン」を表示できます。

       

      • 画面キャプチャ

      Notification.BigTextStyle.png

      •  ソースコード
      // NotificationManager
      NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
      // Small and large icon
      int smallIconId = R.drawable.ic_action_search;
      Bitmap largeIconBitmap = BitmapFactory.decodeResource(
          getResources(), R.drawable.ic_launcher);
      //-----------------------------------------------------------------------
      // BigTextStyle
      //-----------------------------------------------------------------------
      Notification notificationBigTextStyle = new Notification.BigTextStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
          .bigText("BigText")
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(0, notificationBigTextStyle);
      

       

      Notification.BigPictureStyle

      BigPictureStyle は「大きな画像(Big Picture)」を表示できます。

       

      • 画面キャプチャ

      Notification.BigPictureStyle.png

      •  ソースコード
      //-----------------------------------------------------------------------
      // BigPictureStyle
      //-----------------------------------------------------------------------
      Notification notificationBigPictureStyle = new Notification.BigPictureStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
      //  .bigLargeIcon(largeIconBitmap) // Notification.Builder#setLargeIcon() を上書き
          .bigPicture(largeIconBitmap)
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(1, notificationBigPictureStyle);

       

      Notification.InboxStyle

      InboxStyle は、複数行の「テキスト(Line)」、「テキスト(Summary Text)」と「小さいアイコン」を表示できます。

      ※8 行目以降は、"..."表示されます

       

      • 画面キャプチャ

      Notification.InboxStyle.png

      •  ソースコード
      //-----------------------------------------------------------------------
      // InboxStyle
      //-----------------------------------------------------------------------
      Notification notificationInboxStyle = new Notification.InboxStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap))
          .addLine("addLine(1)")
          .addLine("addLine(2)")
          .addLine("addLine(3)")
          .addLine("addLine(4)")
          .addLine("addLine(5)")
          .addLine("addLine(6)")
          .addLine("addLine(7)")
          .addLine("addLine(8)") // 8行目以降は"..."で表示される
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle()  を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(2, notificationInboxStyle);

       

      ボタンを追加する

      Notification 作成時、Notification.Builder#addAction() を呼び出すと、ボタンを追加することができます。

      ※最大3つまで追加できます

      ※ボタン押下時のアクションは、PendingIntent で指定します

       

      • 画面キャプチャ

      NotificationWithButtons.png

       

      • ソースコード
      // PendingIntent
      PendingIntent pendingIntent = PendingIntent.getActivity(this,
          0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
      //-----------------------------------------------------------------------
      // BigTextStyle + Button
      //-----------------------------------------------------------------------
      Notification notificationBigTextStyle = new Notification.BigTextStyle(
          new Notification.Builder(this)
              .setContentTitle("ContentTitle")
              .setSmallIcon(smallIconId)
              .setLargeIcon(largeIconBitmap)
              .addAction(android.R.drawable.ic_input_add, "Add", pendingIntent)
              .addAction(android.R.drawable.ic_input_delete, "Delete", pendingIntent))
          .bigText("BigText")
      //  .setBigContentTitle("BigContentTitle") // Notification.Builder#setContentTitle() を上書き
          .setSummaryText("SummaryText")
          .build();
      nm.notify(4, notificationBigTextStyle);
      

      [Android] Google I/O 2012 リンクメモ

      | トラックバック(0) |

      Google 公式サイト

       

      Google I/O 2012 基調講演(Keynote)

       

      Android 4.1 一般向け

       

      Android 4.1 開発者向け

       

      Nexus 7

       

      Nexus Q

       

      Google Glass

      • Googleメガネ Project Glass、1500ドルで予約受付を開始。I/O出席者限定。 - Engadget Japanese
      • Google I/O:スカイダイビングをGoogle Glassで生中継―ベータ版のデベロッパー向け予価、1500ドル

       

      Google Play

       

      Google Compute Engine

       

      Google Drive

      • iOS版 Google Drive クライアント本日提供、Chrome OS版も公開 - Engadget Japanese

       

      Google Docs

       

      Chrome

      • Google Chrome for iOS インプレッション、便利機能ガイド - Engadget Japanese
      • 速報:Google、iOS版 Chrome ブラウザを本日提供。PCやAndroid版と同期 - Engadget Japanese

       

      ChromeBox

      • GoogleI/O 2012で貰ったChromeBoxを分解する - T.D.3rd

       

      ※しばらく(DevFestXまで)は、メンテしようと思います^^

      @shin1ogawa さんの提案で、docs に移行しました。

      →→ Google I/O 2012 リンクメモ - Google ドキュメント

      @shino_merry さん の作品の「いんふぉばたん」の素材を頂いて JCROM テーマをつくりました。

      ※テーマは(本記事の下の方のリンクから)ダウンロードできます

       

      壁紙

      infobar_wallpaper.png

      壁紙はカワイイ顔のどあっぷ。

      ナビキーは手を抜いて機能を表すアイコンを描かなかったので上級者向けです。。。

      ※左から 【Back】 【Menu】 【Home】 【Toggle Status Bar】 【Recents Panel】

       

      ロック画面

      infobar_lockscreen.png

      お腹を撫でるとロック解除ー。

       

      通知トラッキングビュー&通知バー

      infobar_statusbar.png

      Notification は、タップすると光ります。

      通常は読みやすやを優先して暗めの画像にしています。

       

      Launcher の背景

      infobar_launcher.png

      よくみると、背景画像に「いんふぉばたん」が隠れています。

      アプリの読みやすを優先して画像を暗めにしています。

       

      RecentsPanel

      infobar_frame.png

      思わず何度も押してしまう RecentsPanel 。

       

      テーマダウンロード

      http://www.adakoda.com/adakoda/2012/06/25/mytheme.zip ・・・約1MB

       

       

      JCROM 公式サイト

      https://sites.google.com/site/jcromproject/

       

      テーマは、以下のページを参考に決められたファイル名とサイズで作り、

      SD カードに置くだけで自分好みのテーマを使用できます。

      https://sites.google.com/site/jcromproject/home/creating_themes

       

      お絵かきできる人には、是非テーマを作っていただきたいです。

      2012年6月16日(土)午前9時~翌午前1時に NHK-FM で アニソン三昧 があるそうです!

       

      今日は一日○○三昧(まるまるざんまい)

      http://www9.nhk.or.jp/zanmai/program/120616.html

      • 第1部 9:00~11:50
      • 第2部 12:15~18:50
      • 第3部 19:20~25:00

       

      Android 端末でも NHK-FM を聞ける「NHKネットラジオ らじる★らじる 」というアプリがあるので、

      ぜひインストール&予約し、当日アニソン三昧しましょう♪

       

      NHKネットラジオ らじる★らじる - Google Play の Android アプリ

      https://play.google.com/store/apps/details?id=jp.nhk.netradio

      netradio1.png netradio2.png

       

      ※2012/6/16追記

      ・途切れ途切れの再生にならないようにデフォルトでバッファリングが1分に設定されています。
      遅延が気になる方は30秒に変更した方が良いでしょう。

      ・PC 版はこちら → http://www.nhk.or.jp/fm/

       

      過去のアニソン三昧

      • 2006年「今日は一日"アニソン"三昧」
      • 2007年「今日は一日 アニソン三昧SS(セカンド・ステージ)」
      • 2008年「今日は一日 アニソン三昧ファイナル」
      • 2010年「今日は一日 帰ってきたアニソン三昧」

       

      あわせて読みたい

      <<前のページへ 1234567891011

      2016年8月

        1 2 3 4 5 6
      7 8 9 10 11 12 13
      14 15 16 17 18 19 20
      21 22 23 24 25 26 27
      28 29 30 31