359


Shared Elements を動画で実現したいと思っています。

[makeSceneTransitionAnimation](https://developer.android.com/reference/android/app/ActivityOptions.html#makeSceneTransitionAnimation\(android.app.Activity,%20android.util.Pair%3Candroid.view.View,%20java.lang.String%3E...\))
の様に動的に View を共有して Activity の遷移を行いたいのですが、 **API level 21**
未満の場合はどのように実現すればいいでしょうか。

実装方法として Service 等のライフサイクルを横断するストアに View のインスタンスを保持しておき、そのインスタンスを遷移先の View
をすげ替える事で実現できるのではないかと思っていますが、どなたかご存じないでしょうか？

よろしくお願いします。


CC BY-SA 3.0
2014-12-03T03:01:04.937
293
2014-12-05T08:44:56.047
2014-12-05T08:44:56.047
30
745
question
android
Shared Elements による画面遷移を API level 21 未満でも実現する方法はありますか？


推測されている通り、Androidのフレームワークでも一旦Viewを保存しておき、アニメーションを実行しています。

基本的にはActivityOptionsクラスの[makeSceneTransitionAnimation](http://tools.oesf.biz/android-5.0.0_r2.0/xref/frameworks/base/core/java/android/app/ActivityOptions.java#453)をまねるかたちになりそうです。動画の方は、バッファリングなどもあるので難易度が高そうですが...

[code]

    462         ArrayList<String> names = new ArrayList<String>();
    463         ArrayList<View> views = new ArrayList<View>();
    464 
    465         if (sharedElements != null) {
    466             for (int i = 0; i < sharedElements.length; i++) {
                        // このfor文でsharedElementsからViewを取得
    467                 Pair<View, String> sharedElement = sharedElements[i];
    468                 String sharedElementName = sharedElement.second;
    469                 if (sharedElementName == null) {
    470                     throw new IllegalArgumentException("Shared element name must not be null");
    471                 }
    472                 names.add(sharedElementName);
    473                 View view = sharedElement.first;
    474                 if (view == null) {
    475                     throw new IllegalArgumentException("Shared element must not be null");
    476                 }
    477                 views.add(sharedElement.first);
    478             }
    479         }
    480         // アクティビティ終了時のアニメーション準備
    481         ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
    482                 views, false);
    
[/code]

あわせてサポートライブラリを調査してみましたが、 ActivityOptionsCompat
v21での[実装](http://tools.oesf.biz/android-5.0.0_r2.0/xref/frameworks/support/v4/java/android/support/v4/app/ActivityOptionsCompat.java#131)では、API
Level.21以下でのアニメーションは諦めているようで参考にはなりませんでした。

[code]

    131     public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity,
    132             View sharedElement, String sharedElementName) {
    133         if (Build.VERSION.SDK_INT >= 21) { // 諦めの境地
    134             return new ActivityOptionsCompat.ActivityOptionsImpl21(
    135                     ActivityOptionsCompat21.makeSceneTransitionAnimation(activity,
    136                             sharedElement, sharedElementName));
    137         }
    138         return new ActivityOptionsCompat();
    139     }
    
[/code]


CC BY-SA 3.0
2014-12-03T03:50:50.187
298
2014-12-03T03:50:50.187
395
293
answer


英語ですが、DevBytes に実装の仕方を説明した動画があります。

[https://www.youtube.com/watch?v=CPxkoe2MraA&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=75](https://www.youtube.com/watch?v=CPxkoe2MraA&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=75)

基本的な考え方は、標準の遷移アニメーションを無効化した上で遷移先のアニメーション側で 独自のアニメーションを頑張る形になります。

遷移先でアニメーションさせるための情報として、遷移元の画像の位置と大きさを Intent の extra にいれて startActivity します。
動画の中では以下の様なコードを呼び出し側に記述しています。

[code]

            int[] screenLocation = new int[2];
            v.getLocationOnScreen(screenLocation);
            PictureData info = mPicturesData.get(v);
            Intent subActivity = new Intent(ActivityAnimations.this,
                    PictureDetailsActivity.class);
            int orientation = getResources().getConfiguration().orientation;
            subActivity.
                    putExtra(PACKAGE + ".orientation", orientation).
                    putExtra(PACKAGE + ".resourceId", info.resourceId).
                    putExtra(PACKAGE + ".left", screenLocation[0]).
                    putExtra(PACKAGE + ".top", screenLocation[1]).
                    putExtra(PACKAGE + ".width", v.getWidth()).
                    putExtra(PACKAGE + ".height", v.getHeight()).
                    putExtra(PACKAGE + ".description", info.description);
            startActivity(subActivity);
    
            // Windowアニメーションを無効化
            overridePendingTransition(0, 0);
    
[/code]

呼び出される側では、onCreate で extra を取り出してアニメーションを行うのですが、 ひとつポイントがあります。 onCreate
の段階ではレイアウトが完了していないので、 ViewTreeObserver を使用して描画の直前に処理を挿入してあげるとうまくいきます。

[code]

        if (savedInstanceState == null) {
            ViewTreeObserver observer = mImageView.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    
                @Override
                public boolean onPreDraw() {
                    mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
    
                    // ここにアニメーションの処理を記述
    
                    return true;
                }
            });
        }
    
[/code]

動画の中で解説しているコードはこちらからダウンロードできます。

<http://developer.android.com/shareables/devbytes/ActivityAnimations.zip>

コードだけでも参考になるのではないかと思います。


CC BY-SA 3.0
2014-12-04T17:49:19.813
359
2014-12-04T18:10:14.310
2014-12-04T18:10:14.310
319
319
293
answer