56

私のアプリには、少数のフラグメントで構成される ViewPager で構成されるビューが含まれています。これらのフラグメントのいずれかのアイテムをクリックすると、共有要素 (この場合は画像) が、クリックされたコンテンツに関する詳細情報を表示するフラグメントに遷移することが予想されます。

これは、それがどのように見えるべきかの非常に簡単なビデオです:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-114842.mp4

これは Fragment->Fragment トランジションを使用しているだけです。

ViewPager 内に開始フラグメントを配置すると、問題が発生します。これは、ViewPager が、フラグメント トランザクションを処理しているアクティビティのフラグメント マネージャーとは異なる、親フラグメントの子フラグメント マネージャーを使用しているためだと思われます。これが何が起こるかのビデオです:

https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-120029.mp4

上で説明したように、ここでの問題は、子フラグメント マネージャーとアクティビティのフラグメント マネージャーであると確信しています。これが私がどのように移行を行っているかです:

SimpleFragment fragment = new SimpleFragment();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.am_list_pane, fragment, fragment.getClass().getSimpleName());

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    TransitionSet enterTransition = new TransitionSet();
    enterTransition.addTransition(new ChangeBounds());
    enterTransition.addTransition(new ChangeClipBounds());
    enterTransition.addTransition(new ChangeImageTransform());
    enterTransition.addTransition(new ChangeTransform());

    TransitionSet returnTransition = new TransitionSet();
    returnTransition.addTransition(new ChangeBounds());
    returnTransition.addTransition(new ChangeClipBounds());
    returnTransition.addTransition(new ChangeImageTransform());
    returnTransition.addTransition(new ChangeTransform());

    fragment.setSharedElementEnterTransition(enterTransition);
    fragment.setSharedElementReturnTransition(returnTransition);

    transaction.addSharedElement(iv, iv.getTransitionName());
}

transaction.addToBackStack(fragment.getClass().getName());

transaction.commit();

これは、両方のフラグメントがアクティビティのフラグメント マネージャーによって管理されている場合は正常に機能しますが、次のように ViewPager をロードすると:

ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(new Adapter(getChildFragmentManager()));

ViewPager の子はアクティビティによって管理されていないため、動作しなくなりました。

これは Android チームによる見落としですか? これをやってのける方法はありますか?ありがとう。

4

3 に答える 3

39

おそらくあなたはすでにこれに対する答えを見つけていると思いますが、まだ答えを見つけていない場合のために、数時間頭を悩ませた後、私がそれを修正するために行ったことを次に示します.

私が考える問題は、次の 2 つの要因の組み合わせです。

  • Fragments遅延を伴うインロード。ViewPagerつまり、アクティビティは、ViewPager

  • あなたが私のような人なら、あなたViewPagerの子フラグメントはおそらく同じタイプです。つまり、それらはすべて同じトランジション名 (xml レイアウトで設定した場合) を共有しますが、コードでそれらを設定し、表示されている fragment で一度だけ設定する場合を除きます

これらの問題の両方を修正するために、これが私がしたことです:

1.読み込み遅延の問題を修正:

アクティビティ ( を含むもの) 内で、次の行を の前後ViewPagerに追加します。super.onCreate()setContentView()

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActivityCompat.postponeEnterTransition(this); // This is the line you need to add

    setContentView(R.layout.feeds_content_list_activity);
    ...
}

2. 同じトランジション名を持つ複数のフラグメントの問題を修正:

現在、これを行うにはかなりの方法がありますが、これが「詳細」アクティビティ内で最終的に得られたものです。つまり、を含むアクティビティですViewPageronCreate()実際にはどこでも実行できます):

_viewPager.setAdapter(_sectionsPagerAdapter);
_viewPager.setCurrentItem(position);
...
...
_pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic));

Activityがまだフラグメントにアタッチされていない可能性があるため、注意が必要ですViewPager。そのため、リソースからロードする場合は、アクティビティからフラグメントにトランジション名を渡す方が簡単です。

実際の実装は、予想どおり簡単です。

public void setTransitionName(String transitionName) {
    _transitionName = transitionName;
}

次に、フラグメントの 内に、次のonViewCreated()行を追加します。

public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    ...
    if (_transitionName != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        setTransitionNameLollipop();
    }
    ...
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setTransitionNamesLollipop() {
    _imgTopic.setTransitionName(_transitionName);
}

パズルの最後のピースは、フラグメントが完全にロードされたときを見つけてから を呼び出すことActivityCompat.startPostponedEnterTransition(getActivity());です。

私の場合、UI スレッドからほとんどのものをロードしているため、フラグメントは後で完全にロードされませんでした。つまり、すべてがロードされたときにこれを呼び出す方法を見つけなければなりませんでしたが、そうでない場合は、これを呼び出すことができますあなたが電話した直後setTransitionNameLollipop()

exitこのアプローチの問題は、非常に注意して、アクティビティが戻る直前に「可視」フラグメントのトランジション名をリセットしない限り、終了トランジションが機能しない可能性があることです。それは次のように簡単に行うことができます:

  1. でページの変更を聞くViewPager
  2. フラグメントが見えなくなったらすぐにトランジション名を削除します
  3. 可視フラグメントにトランジション名を設定します。
  4. を呼び出す代わりにfinish()ActivityCompat.finishAfterTransition(activity);

私の場合、バックトランジションが a にトランジションする必要がある場合、これはすぐに非常に複雑になる可能性がRecyclerViewあります。そのために、@Alex Lockwood が提供するはるかに優れた回答があります: ViewPager Fragments – Shared Element Transitionsには、非常によく書かれたサンプル コードがあります (ただし、私が書いたものよりもはるかに複雑です): https://github.com /alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/activity/transitions

私の場合、彼のソリューションを実装するまでに行く必要はなく、投稿した上記のソリューションが私のケースで機能しました。

複数の共有要素がある場合は、それらに対応するためにメソッドを拡張する方法を理解できると確信しています。

于 2015-06-29T19:13:02.793 に答える
1

活動について supportPostponeEnterTransition();

そして、フラグメントがロードされたとき (おそらく EventBus などと同期してみてください)

startPostponedEnterTransition();

このサンプルを参照してください

http://www.androiddesignpatterns.com/2015/03/activity-postponed-shared-element-transitions-part3b.html

于 2015-06-21T19:34:40.413 に答える