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());

* 旧解决方案 *

最好的选择是这里的第二种解决方案:http: //tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

简而言之:您跟踪所有“活动”片段页面。在这种情况下,您在 FragmentStatePagerAdapter 中跟踪片段页面,ViewPager..

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 获得 Fragment,你只需要调用:

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 的默认实现直接从 FragmentManager 恢复片段,而不调用 getItem() 方法。这意味着您将永远没有机会存储对您的片段的引用。

有关详细信息,请参阅源代码: 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 回答
1

正如@Lancelot 提到的,您可以调用并将结果转换为您的 SuperCoolFragment:

SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position); 
于 2015-11-11T12:57:46.627 回答
0

我尝试了弗兰克的回答,它建议从其中链接的教程中使用第二种方法,由于某种原因,在将方法 getFragment() 添加到我的 ViewPagerAdapter 之后,我无法通过 mViewPager.getAdapter 访问它。getFragment () 就好像它不存在一样,所以我将 mPageReferenceMap 声明从 ViewPagerAdapter 移动到封闭类,以便从封闭类的任何点轻松访问它(在我的情况下,它是 MainActivity 来自其他片段的回调方法)最后使得在片段之间传递数据成为可能。感谢 Frank,如果您喜欢我在访问自定义 getFragment 方法时遇到问题,请随时实施我的夹具。

于 2015-06-30T20:48:31.673 回答
0

另一种解决方案是复制粘贴FragmentStatePagerAdapter的源代码并添加一个getFragment方法:

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

覆盖setPrimaryItem,并使用该位置,它将是正确的页面索引:

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container,position,object);
        if (position == 1) {
            currentPageIndex=cameraFragment.pageIndex;
}
于 2016-10-08T08:44:10.917 回答
-10

创建一个持有者来保存新的 SuperCoolFragment 对象。然后标记并返回持有者对象。

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