public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
A similar approach to getItem() above but non-lifecycle-breaking 这是挂钩到 instantiateItem() 而不是 getItem() ,因为每次创建/访问索引时都会调用前者 . 见this answer
A HAPPY PATH:构建自己的FragmentViewPager
从source of the latest support lib构造您自己的 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,则可以知道结果 may be null 页面即尚未创建 .
/**
* @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;
}
这是一个简单的解决方案,可以解决网络上随处可见的其他两种解决方案中的问题
2
将以下方法添加到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;
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
//...
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}
21
我知道这有几个答案,但也许这会对某人有所帮助 . 当我需要从 ViewPager 获得 Fragment 时,我使用了一个相对简单的解决方案 . 在 Activity 或 Fragment 中持有 ViewPager ,您可以使用此代码循环查看它所持有的每个 Fragment .
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
if(viewPagerFragment != null) {
// Do something with your Fragment
// Check viewPagerFragment.isResumed() if you intend on interacting with any views.
}
}
如果你知道 Fragment 中 Fragment 的位置,你可以调用 getItem(knownPosition) .
我发现 getItem 仅在 FragmentPagerAdapter 需要创建 first time 时被 FragmentPagerAdapter 调用,之后,使用 FragmentManager 回收 Fragments . 这个在 getItem 中, FragmentPagerAdapter 创建 newFragment 的许多实现方式 . 使用我的上述方法,这意味着我们将在每次 getItem 被调用时创建新的 Fragment ,因为我们遍历了 FragmentPagerAdapter 中的所有项目 . 因此,我找到了一个更好的方法,使用 FragmentManager 来获取每个 Fragment (使用接受的答案) . 这是一个更完整的解决方案,并且一直很适合我 .
FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
String name = makeFragmentName(mViewPager.getId(), i);
Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
// OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
if(viewPagerFragment != null) {
// Do something with your Fragment
if (viewPagerFragment.isResumed()) {
// Interact with any views/data that must be alive
}
else {
// Flag something for update later, when this viewPagerFragment
// returns to onResume
}
}
}
@Override
onCreate(){
//initialise the list of fragments
fragments = new Vector<Fragment>();
//fill up the list with out fragments
fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));
//Set up the pager
pager = (ViewPager)findViewById(R.id.pager);
pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
pager.setOffscreenPageLimit(4);
}
所以这可以称为:
public Fragment getFragment(ViewPager pager){
Fragment theFragment = fragments.get(pager.getCurrentItem());
return theFragment;
}
所以我可以把它放在if语句中,只有当它在正确的片段上时才会运行
Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
//then you can do whatever with the fragment
theFrag.costomFunction();
}
但这只是我的黑客和斜线方法,但它对我有用,我用它做按下后退按钮时对我当前显示的片段进行相关更改 .
2
你 don't 需要在后期调用 getItem() 或其他一些方法来获取 ViewPager 中托管的 Fragment 的引用 . 如果要更新 Fragment 中的某些数据,请使用以下方法:Update ViewPager dynamically?
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;
}
public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}
在你的适配器:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private final ActionBar actionBar;
private final FragmentManager fragmentManager;
public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}
@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}
@Override
public int getCount() {
return this.actionBar.getTabCount();
}
@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}
private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}
}
0
Fragment yourFragment = yourviewpageradapter.getItem(int index);
index 是适配器中片段的位置,就像你先添加 fragment1 所以retreive fragment1 传递 index 为0等等休息
23 回答
主要答案依赖于框架生成的名称 . 如果这种情况发生了变化,那么它将不再起作用 .
这个解决方案怎么样,覆盖
Fragment(State)PagerAdapter
的instantiateItem()
和destroyItem()
:在处理可用的碎片时,这似乎对我有用 . 尚未实例化的片段在调用
getRegisteredFragment
时将返回null . 但是我一直在使用这个来获取当前的Fragment
ViewPager
:adapater.getRegisteredFragment(viewPager.getCurrentItem())
并且这不会返回null
.我不知道这个解决方案的任何其他缺点 . 如果有的话,我想知道 .
为了从ViewPager中抓取片段,这里和其他相关的SO线程/博客上有很多答案 . 我见过的每个人都被打破了,他们似乎一般都属于下面列出的两种类型之一 . 如果您只想获取当前片段,还有一些其他有效的解决方案,例如this此线程上的其他答案 .
如果使用 FragmentPagerAdapter 见下文 . 如果使用 FragmentStatePagerAdapter 其值得看this . 在FragmentStateAdapter中抓取不是当前索引的索引并不像它的本质那样有用,这些索引将完全拆除掉在offScreenLimit边界之外 .
不适当的路径
Wrong: Maintain your own internal list of fragments, added to when FragmentPagerAdapter.getItem() is called
通常使用
SparseArray
或Map
我见过生命周期事件的许多例子中没有一个,所以这个解决方案很脆弱 . 由于
getItem
仅在ViewPager
中第一次滚动页面(或者如果ViewPager.setOffscreenPageLimit(x)
> 0获得)时被调用,如果主机Activity
/Fragment
被终止或重新启动,则在重新创建自定义FragmentPagerActivity时将清除内部SpaseArray
,但在幕后,将重新创建ViewPagers内部片段,并且getItem
将为任何索引调用 NOT ,因此从索引获取片段的能力将永远丢失 . 您可以通过FragmentManager.getFragment()
和putFragment
保存并恢复这些片段引用来解决这个问题,但这开始变得混乱恕我直言 .Wrong: Construct your own tag id matching what is used under the hood in FragmentPagerAdapter 并使用此方法从
FragmentManager
检索页面碎片为此解决方案重新创建的方法是
A HAPPY PATH:ViewPager.instantiateItem()
A similar approach to getItem() above but non-lifecycle-breaking 这是挂钩到
instantiateItem()
而不是getItem()
,因为每次创建/访问索引时都会调用前者 . 见this answerA HAPPY PATH:构建自己的FragmentViewPager
从source of the latest support lib构造您自己的
FragmentViewPager
类,并更改内部使用的方法以生成片段标记 . 您可以使用以下内容替换它 . 这样做的好处是,您知道标签创建永远不会改变,并且您不依赖于私有API /方法,这总是很危险 .然后正如文档所说,当你想要获取用于索引的片段时,只需调用类似于此方法(可以放入自定义
FragmentPagerAdapter
或子类中)的方法,如果尚未调用getItem,则可以知道结果 may be null 页面即尚未创建 .这是一个简单的解决方案,可以解决网络上随处可见的其他两种解决方案中的问题
将以下方法添加到FragmentPagerAdapter:
getActiveFragment(0)必须工作 .
以下是ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d中实现的解决方案 . 如果出现故障,您将看到良好的崩溃日志 .
另一个简单的解决
我知道这有几个答案,但也许这会对某人有所帮助 . 当我需要从
ViewPager
获得Fragment
时,我使用了一个相对简单的解决方案 . 在Activity
或Fragment
中持有ViewPager
,您可以使用此代码循环查看它所持有的每个Fragment
.如果你知道
Fragment
中Fragment
的位置,你可以调用getItem(knownPosition)
.如果您不知道
ViewPager
中Fragment
的位置,您可以让您的孩子Fragments
使用getUniqueId()
等方法实现接口,并使用它来区分它们 . 或者你可以遍历所有Fragments
并检查类类型,例如if(viewPagerFragment instanceof FragmentClassYouWant)
!!! EDIT !!!
我发现
getItem
仅在FragmentPagerAdapter
需要创建 first time 时被FragmentPagerAdapter
调用,之后,使用FragmentManager
回收Fragments
. 这个在getItem
中,FragmentPagerAdapter
创建 newFragment
的许多实现方式 . 使用我的上述方法,这意味着我们将在每次getItem
被调用时创建新的Fragment
,因为我们遍历了FragmentPagerAdapter
中的所有项目 . 因此,我找到了一个更好的方法,使用FragmentManager
来获取每个Fragment
(使用接受的答案) . 这是一个更完整的解决方案,并且一直很适合我 .你需要这种方法 .
就我而言,上述解决方案均无效 .
但是,由于我在Fragment中使用Child Fragment Manager,因此使用了以下内容:
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
这仅在Manager中的片段对应于viewpager项时才有效 .
这是基于史蒂文上面的答案 . 这将返回已附加到父活动的片段的实际实例 .
我找不到一个简单,干净的方法来做到这一点 . 但是,ViewPager小部件只是另一个ViewGroup,它托管您的片段 . ViewPager将这些片段作为直接子元素 . 所以你可以迭代它们(使用.getChildCount()和.getChildAt()),看看你正在寻找的片段实例当前是否已加载到ViewPager并获得对它的引用 . 例如 . 您可以使用一些静态唯一ID字段来区分碎片 .
请注意,ViewPager可能尚未加载您正在查找的片段,因为它是像ListView这样的虚拟化容器 .
FragmentPagerAdapter是片段的工厂 . 要在仍然在内存中的情况下根据其位置查找片段,请使用以下命令:
v4支持api的示例代码 .
我通过首先制作我将要使用的所有片段(
List<Fragment> fragments;
)的列表来处理它,然后将它们添加到寻呼机中,以便更容易处理当前查看的片段 .所以:
所以这可以称为:
所以我可以把它放在if语句中,只有当它在正确的片段上时才会运行
但这只是我的黑客和斜线方法,但它对我有用,我用它做按下后退按钮时对我当前显示的片段进行相关更改 .
你 don't 需要在后期调用
getItem()
或其他一些方法来获取ViewPager
中托管的Fragment
的引用 . 如果要更新Fragment
中的某些数据,请使用以下方法:Update ViewPager dynamically?关键是在
Adaper
中设置新数据并调用notifyDataSetChanged()
,然后调用getItemPosition()
,向您传递Fragment
的引用并让您有机会更新它 . 所有其他方式都要求您继续引用自己或其他一些不是很好的解决方案 .必须将
FragmentPagerAdapter
扩展到ViewPager适配器类中 .如果您使用
FragmentStatePagerAdapter
那么您将无法通过其ID
找到您的Fragment
如何使用这种方法: -
嘿,我已经回答了这个问题here . 基本上,你需要覆盖
FragmentStatePagerAdapter的方法 .
最佳解决方案是使用我们在CodePath创建的名为SmartFragmentStatePagerAdapter的扩展 . 遵循该指南,这使得从ViewPager检索片段和当前选择的片段变得更加容易 . 它还可以更好地管理嵌入在适配器中的片段的内存 .
最简单,最简洁的方式 . 如果
ViewPager
中的所有片段属于不同的类,您可以检索并区分它们如下:我用一种不同的方法实现了这一点 .
我的自定义FragmentAdapter.getItem方法返回的不是新的MyFragment(),而是在FragmentAdapter构造函数中创建的MyFragment实例 .
在我的活动中,我从适配器获取片段,检查它是否是instanceOf需要片段,然后转换并使用所需的方法 .
在/values/integers.xml中创建整数资源ID
然后在PagerAdapter getItem函数中:
然后在activity中编写此函数以获取片段引用:
通过调用上面的函数获取片段引用,然后将其转换为自定义片段:
在片段管理器中迭代片段的简便方法 . 查找具有section位置参数的viewpager,放置在public static PlaceholderFragment newInstance(int sectionNumber)中 .
在片段中
在FragmentActivity中
在TabLayout中,Fragment有多个选项卡 . 你可以使用片段的索引通过Tag找到片段 .
对于前者Fragment1的索引是0,所以在
findFragmentByTag()
方法中,传递Viewpager的标签 . 使用fragmentTransaction你可以添加,替换片段 .String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
好的适配器
FragmentStatePagerAdapter
我资助一个解决方案:在FragmentActivity中:
并在你的类FragmentActivity中创建一个方法 - 所以这个方法可以让你访问你的片段,你只需要给它你想要的片段的位置:
在你的适配器:
index
是适配器中片段的位置,就像你先添加fragment1
所以retreivefragment1
传递index
为0等等休息