web-dev-qa-db-ja.com

ViewPagerフラグメント–共有要素の遷移

私が開発しているアプリは、画像のグリッドを表示します。画像をタップすると、詳細ビ​​ューに移動します。詳細ビューには、グリッド内のすべての画像間をスワイプできるViewPagerが含まれています。これは、パスのリスト(グリッド内のすべての画像を含む)とタップされた画像のオフセットを渡すことで行われ、ViewPagerがそのページを最初に表示するように設定できます。

ViewPagerの現在のオフセットページのフラグメント内で共有要素の遷移を行うための最良の方法は何ですか?グリッド(RecyclerView)画像は、現在のページの全画面画像に展開されます。アクティビティの遷移を延期および再開する機能を確認したので、画像がディスクから読み込まれるまで、アプリは共有要素の遷移を表示するのを待ちます。しかし、私はそれをビューページャーの正しいページにアニメーション化し、ユーザーが戻ったときに現在のページが何であっても終了できるようにしたいと考えています(ページ間をスワイプできるため)。ここで別のページにスワイプすると、最初のページがグリッドにアニメーション表示されます。

現在、ビューページャーのフラグメント内のすべての画像に、「image_ [index]」という形式のtransitionNameを割り当てています。詳細アクティビティを開始するときは、同じtransitionNameを使用して、インデックスをオフセットにしています。

これに関連して、長押しで波紋をどのように機能させるかについても疑問に思いました。ビューのアクティブ状態を変更すると、波紋がキャンセルされるようです。 Gmailに似た効果が欲しい。さざ波が最初から始まり、長押しが完了するとすぐに終了し、アクティブ化された状態がトリガーされる。

26
afollestad

私が言えること(そして私が間違っている場合は修正してください)から、あなたが達成しようとしていることは、基本的に次のようなものです:MainActivityDetailsActivity、および任意の画像のセット。 MainActivityは画像のセットをグリッドに表示し、DetailsActivityは同じ画像のセットを水平ViewPagerに表示します。ユーザーがMainActivityの画像を選択すると、その画像はグリッド内の位置から2番目のアクティビティのViewPagerの正しいページに遷移する必要があります。

私たちが解決したい問題は、「ユーザーがDetailsActivity内のページを切り替えたらどうなるか」です。これが発生した場合は、戻り遷移中に使用される共有イメージを変更します。デフォルトでは、アクティビティ遷移フレームワークは、遷移の開始時に使用された共有要素を使用しますが、ページャーのページが変更されているため、この動作を何らかの方法でオーバーライドする必要があります。そのためには、SharedElementCallbackおよびMainActivityonCreate()メソッドにDetailsActivityを設定し、onMapSharedElements()メソッドをオーバーライドする必要がありますそのようです:

private final SharedElementCallback mCallback = new SharedElementCallback() {
    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        if (mCurrentImagePosition != mOriginalImagePosition) {
            View sharedView = getImageAtPosition(mCurrentImagePosition);
            names.clear();
            sharedElements.clear();
            names.add(sharedView.getTransitionName());
            sharedElements.put(sharedView.getTransitionName(), sharedView);
        }
    }

    /**
     * Returns the image of interest to be used as the entering/returning
     * shared element during the activity transition.
     */
    private View getImageAtPosition(int position) {
        // ...
    }
};

より完全なソリューションとして、この効果を実現する サンプルプロジェクトをGitHub に作成しました(コードが多すぎる)単一のStackOverflow回答で投稿します)。

34
Alex Lockwood

フラグメント遷移を使用していて、アクティビティ間でアニメーション化していないことを前提としています。アクティビティ遷移とフラグメント遷移の両方で可能ですが、特定のコードは少し異なります。ただし、Fragment Transitionsでは延期できません。

AddSharedElementは2番目のパラメーターを取ります。呼び出すときにターゲットフラグメントの特定の名前がわかっている場合は、使用する詳細フラグメントの名前を選択できます。そうでない場合は、任意の名前を選択して、Fragmentに設定されたSharedElementCallbackを使用して再マッピングできます。

fragment.setEnterSharedElementCallback(new SharedElementCallback() {
    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        sharedElements.put("detailView", mTargetDetailView);
    }
});

戻るときに一致しない場合は、同じ呼び出しを行って再マッピングします。これは、呼び出しフラグメントと呼び出しフラグメントの両方に存在する可能性があります。呼び出しフラグメントでは、setExitSharedElementCallbackを使用します。これはあなたのアプリにも当てはまると思います。

同様に、アクティビティの遷移では、同じSharedElementCallbackを設定して同じマッピングを使用しますが、代わりにアクティビティで行います。

3
George Mount