23

を使用するFragmentStatePageAdapterと、次のようなフラグメントが得られます。

    @Override
    public Fragment getItem(int position) {
        return new SuperCoolFragment();
    }

ただし、コードの後半で、このフラグメントを見つけてプロパティを設定する必要があります。フラグメントを使用するアプリの他の部分では、基本的にフラグメントにタグを付けて検索しますfindFragmentByTag(TAG)が、今ではその方法がわかりません。

を使用してフラグメントを見つけるにはどうすればよいFragmentStatePageAdapterですか?

4

10 に答える 10

49

* 編集 *

@ElliotM が指摘したように、より良い解決策があります。アダプターで何も変更する必要はありません。次のようにフラグメントを取得するだけです。

Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem());

* 古いソリューション *

最良のオプションは、ここでの 2 番目のソリューションです

つまり、すべての「アクティブな」フラグメント ページを追跡します。この場合、ViewPager で使用される FragmentStatePagerAdapter でフラグメント ページを追跡します。

public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

「非アクティブな」フラグメント ページへの参照を保持しないようにするには、FragmentStatePagerAdapter の destroyItem(...) メソッドを実装する必要があります。

public void destroyItem(View container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

...そして、現在表示されているページにアクセスする必要がある場合は、次を呼び出します。

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

... MyAdapter の getFragment(int) メソッドは次のようになります。

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

- - 編集:

また、向きを変更した後のために、これをアダプターに追加します。

/**
 * After an orientation change, the fragments are saved in the adapter, and
 * I don't want to double save them: I will retrieve them and put them in my
 * list again here.
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
    MyFragment fragment = (MyFragment) super.instantiateItem(container,
            position);
    mPageReferenceMap.put(position, fragment);
    return fragment;
}
于 2013-02-13T08:00:35.950 に答える
15

別の方法を見つけましたが、使用に問題があるかどうかはわかりませんが、問題ないようです。

FragmentStatePageAdapterのコードをチェックしていたところ、次のメソッドが表示されました。

@Override
52     public Object More ...instantiateItem(View container, int position) {
53         // If we already have this item instantiated, there is nothing
54         // to do.  This can happen when we are restoring the entire pager
55         // from its saved state, where the fragment manager has already
56         // taken care of restoring the fragments we previously had instantiated.
57         if (mFragments.size() > position) {
58             Fragment f = mFragments.get(position);
59             if (f != null) {
60                 return f;
61             }
62         }
63 
64         if (mCurTransaction == null) {
65             mCurTransaction = mFragmentManager.beginTransaction();
66         }
67 
68         Fragment fragment = getItem(position);
69         if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
70         if (mSavedState.size() > position) {
71             Fragment.SavedState fss = mSavedState.get(position);
72             if (fss != null) {
73                 fragment.setInitialSavedState(fss);
74             }
75         }
76         while (mFragments.size() <= position) {
77             mFragments.add(null);
78         }
79         fragment.setMenuVisibility(false);
80         mFragments.set(position, fragment);
81         mCurTransaction.add(container.getId(), fragment);
82 
83         return fragment;
84     }

このメソッドを使用して、その特定の位置にすでに設置されているフラグメントを取得できます。したがって、フラグメントを位置 1 で取得したい場合は、次のように呼び出すだけです。

myFragmentStatePageAdpater.instantiateItem(null, 1)

それが役立つことを願っています

于 2014-03-04T16:20:46.677 に答える
5

getItemTag(int position)に関数を追加することでこれを実装しましたFragmentStatePagerAdapter。他の誰かがこのルートに行きたい場合は、更新されたファイルのドロップイン バージョンがここにあります。

于 2013-07-15T09:33:40.063 に答える
2

アクティビティが再作成された場合、 getItem() メソッドでフラグメントを HashMap に格納するソリューションは機能しません!

問題は、FragmentStatePagerAdapter のデフォルトの実装が、getItem() メソッドを呼び出さずに FragmentManager からフラグメントを直接復元することです。これは、フラグメントへの参照を保存する機会が決して得られないことを意味します。

詳細については、ソース コードを参照してください: FragmentStatePagerAdapter#restoreState

これは基本的に、フラグメントへの参照を取得する唯一の方法はリフレクションに頼ることであることを意味します。サポート ライブラリを使用している場合、これは比較的*安全です**。

方法は次のとおりです。

    @SuppressWarnings("unchecked")
    public Fragment getFragment(int position) {
        try {
            Field f = FragmentStatePagerAdapter.class.getDeclaredField("mFragments");
            f.setAccessible(true);
            ArrayList<Fragment> fragments = (ArrayList<Fragment>) f.get(this);
            if (fragments.size() > position) {
                return fragments.get(position);
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

相対的に* は、フレームワーク クラスでリフレクションを使用するほど危険ではないことを意味します。サポート クラスはアプリにコンパイルされます。このコードがデバイスで機能することはありませんが、他のデバイスではクラッシュします。サポート ライブラリを新しいバージョンに更新することで、このソリューションを壊す可能性があります。

安全** 反射を使用することは決して安全ではありません。ただし、使用しているライブラリに設計上の欠陥がある場合は、この方法に頼る必要があります。

于 2013-12-18T19:20:08.193 に答える
1

カスタムタグをFragmentStateAdapter設定して探すのはとても簡単です。FragmentStateAdapterフラグメントにタグを付ける方法は次のとおりです。

mFragmentManager.beginTransaction()
    .add(fragment, "f" + holder.getItemId())
    .setMaxLifecycle(fragment, STARTED)
    .commitNow();

ご覧のとおり、静的文字列"f"getItemId(). アダプターでオーバーライドfun getItemId(position: Int): Longした後、特定のフラグメントを見つけるのは簡単です。例えば

override fun getItemId(position: Int): Long {
    return if(position == 0) {
            "my_first_fragment"
    }else "my_second_fragment"
}

最初のフラグメントのタグは「fmy_first_fragment」で、childFragmentManager.findFragmentByTag("fmy_first_fragment") as? MyFirstFragment

フラグメントを探すときは常に注意してください。フラグメントの作成に使用したものと同じ FragmentManager を使用する必要があります。そのため、コンストラクターとして FragmentManager と LifeCycle を使用してアダプターを作成することをお勧めします。

于 2022-02-10T15:22:27.313 に答える
0

もう 1 つの解決策は、 FragmentStatePagerAdapterのソース コードをコピーして貼り付け、getFragmentメソッドを追加することです。

public Fragment getFragment(int position) {
    if (position >= mFragments.size()) {
        return null;
    }
    return mFragments.get(position);
}
于 2015-08-21T10:35:14.883 に答える
0

ViewPagerAdapter にメソッド getFragment() を追加した後、なんらかの理由でボットにリンクされているチュートリアルからセカンドアプローチを提案するフランクの答えを試しました mViewPager.getAdapter 経由でアクセスできません。getFragment () が存在しないかのように、mPageReferenceMap 宣言を ViewPagerAdapter から囲んでいるクラスに移動して、囲んでいるクラスの任意のポイントから簡単にアクセスできるようにしました (私の場合は、他のフラグメントからの MainActivity のコールバック メソッドです)。フラグメント間でデータを渡すことができます。カスタム getFragment メソッドへのアクセスで問題が発生する場合は、Frank に感謝します。私のフィクスチャを自由に実装してください。

于 2015-06-30T20:48:31.673 に答える
-10

新しい SuperCoolFragment オブジェクトを保持するホルダーを作成します。次に、ホルダー オブジェクトにタグを付けて返します。

@Override
public Fragment getItem(int position) {
    SuperCoolFragment superCoolFragment = new SuperCoolFragment();
    superCoolFragment.setTag(YOUR_TAG);
    return superCoolFragment;
}
于 2012-09-12T09:44:12.080 に答える