我使用一个ViewPager和一个FragmentStatePagerAdapter来托管三个不同的片段:
(Fragment1) (Fragment2) (Fragment3)
当我想从FragmentActivity中的ViewPager中获取Fragment1时。
问题是什么,我该如何解决它?
我使用一个ViewPager和一个FragmentStatePagerAdapter来托管三个不同的片段:
(Fragment1) (Fragment2) (Fragment3)
当我想从FragmentActivity中的ViewPager中获取Fragment1时。
问题是什么,我该如何解决它?
当前回答
为FragmentPagerAdapter添加下一个方法:
public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return mFragmentManager.findFragmentByTag(name);
}
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
getActiveFragment(0)必须工作。
下面是在ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d中实现的解决方案。如果出现故障,你会看到良好的崩溃日志。
其他回答
在/values/integers.xml中创建整数资源id
<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>
然后在PagerAdapter中使用getItem函数:
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0) {
fragment = FragmentOne.newInstance();
mViewPager.setTag(R.integer.page1,fragment);
}
else if (position == 1) {
fragment = FragmentTwo.newInstance();
mViewPager.setTag(R.integer.page2,fragment);
} else if (position == 2) {
fragment = FragmentThree.newInstance();
mViewPager.setTag(R.integer.page3,fragment);
}
return fragment;
}
然后在activity中写这个函数来获取片段引用:
private Fragment getFragmentByPosition(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = (Fragment) mViewPager.getTag(R.integer.page1);
break;
case 1:
fragment = (Fragment) mViewPager.getTag(R.integer.page2);
break;
case 2:
fragment = (Fragment) mViewPager.getTag(R.integer.page3);
break;
}
return fragment;
}
通过调用上面的函数来获取片段引用,然后将其转换为自定义片段:
Fragment fragment = getFragmentByPosition(position);
if (fragment != null) {
FragmentOne fragmentOne = (FragmentOne) fragment;
}
你不需要在后面的阶段调用getItem()或其他方法来获取托管在ViewPager内部的Fragment的引用。如果你想在Fragment中更新一些数据,那么使用这种方法:动态更新ViewPager ?
关键是在Adaper中设置新数据并调用notifyDataSetChanged(),后者将调用getItemPosition(),传递给你Fragment的引用并让你有机会更新它。所有其他方法都需要你参考自己或其他方法,这不是一个好的解决方案。
@Override
public int getItemPosition(Object object) {
if (object instanceof UpdateableFragment) {
((UpdateableFragment) object).update(xyzData);
}
//don't return POSITION_NONE, avoid fragment recreation.
return super.getItemPosition(object);
}
Must将FragmentPagerAdapter扩展到你的ViewPager适配器类。 如果你使用FragmentStatePagerAdapter,那么你将无法通过它的ID找到你的Fragment
public static String makeFragmentName(int viewPagerId, int index) {
return "android:switcher:" + viewPagerId + ":" + index;
}
如何使用这种方法:-
Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;
对于从ViewPager中抓取片段,在这里和其他相关的SO线程/博客上有很多答案。我见过的每个人都很坏,他们通常属于下面列出的两种类型之一。如果你只想抓取当前片段,还有一些其他有效的解决方案,比如这个线程上的其他答案。
如果使用FragmentPagerAdapter参见下面。如果使用FragmentStatePagerAdapter,值得一看。抓取不是FragmentStateAdapter中当前索引的索引并没有那么有用,因为从本质上讲,这些索引将完全被删除,离开视图/ offScreenLimit边界。
不幸的道路
错误:维护自己的内部片段列表,当FragmentPagerAdapter.getItem()被调用时添加
Usually using a SparseArray or Map Not one of the many examples I have seen accounts for lifecycle events so this solution is fragile. As getItem is only called the first time a page is scrolled to (or obtained if your ViewPager.setOffscreenPageLimit(x) > 0) in the ViewPager, if the hosting Activity / Fragment is killed or restarted then the internal SpaseArray will be wiped out when the custom FragmentPagerActivity is recreated, but behind the scenes the ViewPagers internal fragments will be recreated, and getItem will NOT be called for any of the indexes, so the ability to get a fragment from index will be lost forever. You can account for this by saving out and restoring these fragment references via FragmentManager.getFragment() and putFragment but this starts to get messy IMHO.
错误:构造自己的标签id,匹配在FragmentPagerAdapter中使用的内容,并使用它从FragmentManager中检索页面片段
这在处理第一个内部数组解决方案中丢失片段引用的问题上是更好的,但正如上面和网上其他地方的答案中正确指出的那样——它是ViewPager内部的私有方法,可以在任何时间或任何OS版本中更改,这让人感觉很不舒服。
为这个解决方案重新创建的方法是
private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
viewpage . instantiateitem ()
与上面的getItem()类似但不破坏生命周期的方法是钩子到instantiateItem()而不是getItem(),因为前者将在每次创建/访问索引时调用。请看这个答案
快乐之路:构建你自己的FragmentViewPager
从最新支持库的源代码中构造您自己的FragmentViewPager类,并更改用于生成片段标记的内部方法。你可以用下面的替换。这样做的好处是,你知道标签的创建永远不会改变,而且你不依赖于私有api /方法,这总是很危险的。
/**
* @param containerViewId the ViewPager this adapter is being supplied to
* @param id pass in getItemId(position) as this is whats used internally in this class
* @return the tag used for this pages fragment
*/
public static String makeFragmentName(int containerViewId, long id) {
return "android:switcher:" + containerViewId + ":" + id;
}
然后,正如文档所说,当你想抓取一个片段用于索引只是调用像这样的方法(你可以把自定义FragmentPagerAdapter或一个子类)意识到,如果getItem还没有被调用的页面,即它还没有被创建,结果可能是空的。
/**
* @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
* yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
* the current positions fragment.
*/
public @Nullable Fragment getFragmentForPosition(int position)
{
String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
return fragment;
}
这是一个简单的解决方案,解决了其他两个解决方案在网络上随处可见的问题
我找不到一个简单干净的方法来做这件事。然而,ViewPager小部件只是另一个ViewGroup,它承载着你的片段。ViewPager将这些片段作为直接子片段。所以你可以遍历它们(使用. getchildcount()和. getchildat()),看看你正在寻找的片段实例当前是否加载到ViewPager中,并获得对它的引用。例如,你可以使用一些静态的唯一ID字段来区分片段。
注意,ViewPager可能没有加载你正在寻找的片段,因为它是一个像ListView一样的虚拟化容器。