如何在 MainActivity 中获取 ViewPager 创建的 Fragment 的元素?

我有几个用 ViewPager 组织的片段.我将 addOnPageChangeListener 添加到 MainActivity 的 onCreate 方法中的 ViewPager 中,该方法给出了所选片段的位置.

即使我通过声明 setOffscreenPageLimit 来防止 Fragment 自行破坏,但我仍然没有弄清楚如何从 MainActivity 访问 Fragment,因为只需使用 findViewById 返回空对象异常.

我想做的事:

我想访问片段的元素,例如布局和滚动视图,在 ViewPagerOnPageListener 中:

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@覆盖公共无效 onPageSelected(int i) {如果(我 == 0){//对第一个片段做一些事情.}否则如果(我== 1){//对第二个片段做一些事情.}}}

ViewPager 使用 FragmentPagerAdapter:

公共类 SectionsPagerAdapter 扩展 FragmentPagerAdapter {公共 SectionsPagerAdapter(FragmentManager fm) {超级(调频);}@覆盖公共片段getItem(int位置){开关(位置){案例0:返回 Fragment1.newInstance(位置);情况1:返回 Fragment2.newInstance(位置);案例2:返回 Fragment3.newInstance(位置);案例3:返回 Fragment4.newInstance(位置);默认:抛出新的 IllegalArgumentException();}}@覆盖公共 int getCount() {返回 4;}}

是这样添加的:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());mViewPager.setAdapter(mSectionsPagerAdapter);

~

或者我应该改变我的方法吗?

如果使用这种设计无法访问片段,那么有效的替代途径是什么?

我曾尝试在自定义ViewPager 中实现ViewPager.onPageChangeListener,但这似乎不是一个好的选择.

我可以处理它们各自片段中的元素,但这是一个乏味的过程并且难以维护,这就是我寻找一种同时处理它们的方法的原因.

我知道以前有人问过类似的问题,但我没有找到解决方案.

解决方案

不幸的是,唯一的安全"方法是检查FragmentPagerAdapter的源代码,并查看添加片段的 tag 是什么 - 因为 findFragmentByTag 是从 FragmentManager 获取片段的唯一安全方法.

当然,我们需要希望这个实现细节不会在不同的支持库版本之间发生变化,但实际上多年来并没有改变 :)

<小时>

无论如何,FragmentPagerAdapter 说:

<块引用>

//我们是否已经有了这个片段?字符串名称 = makeFragmentName(container.getId(), itemId);片段片段 = mFragmentManager.findFragmentByTag(name);

那么name是什么?

<块引用>

private static String makeFragmentName(int viewId, long id) {返回 "android:switcher:" + viewId + ":" + id;}

什么是viewId,什么是id?

ViewId 是 container.getId(),其中 containerViewPager 本身.

id为:final long itemId = getItemId(position);默认为return position;.

<小时>

所以你可以找到片段如下:

片段片段 = fragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition);//如果fragment为null,它还没有被ViewPager创建

<小时>

注意:

值得注意的是,您不应该依赖 getItem(int position) { 来返回 与您传入的片段实例相同的片段实例,因为这会导致您这个问题.(这道题做对了,getItem() 方法必须总是返回一个新的 Fragment 实例.)

I have several fragments which are organized with a ViewPager. I add an addOnPageChangeListener to the ViewPager in MainActivity's onCreate method which gives the position of the selected fragment.

Even though I prevent the fragments from destroying themselves with stating a setOffscreenPageLimit, I still haven't figured out how to access fragments from MainActivity, as simply using findViewById returns null object exceptions.

What I want to do:

I would like to access elements of fragments, e.g. layouts and scrollviews, in the OnPageListener of the ViewPager:

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override
    public void onPageSelected(int i) {

        if(i == 0) {
            // Do something with the first fragment.
        } else if(i == 1) {
            // Do something with the second fragment.
        }

    }

}

The ViewPager uses a FragmentPagerAdapter:

public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {

        switch (position) {
            case 0:
                return Fragment1.newInstance(position);
            case 1:
                return Fragment2.newInstance(position);
            case 2:
                return Fragment3.newInstance(position);
            case 3:
                return Fragment4.newInstance(position);
            default:
                throw new IllegalArgumentException();
        }
    }

    @Override
    public int getCount() {
        return 4;
    }
}

Which is added like this:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mSectionsPagerAdapter);

~

Or should I change my approach?

If accessing fragments cannot be achieved with this design, what could be an effective alternative route?

I've tried to implement ViewPager.onPageChangeListener in the custom ViewPager, but it didn't seem to be a good option.

I could deal with the elements in their respective fragments, but this is a tedious process and hard to maintain, which I the reason I look for a way to handle them simultaneously.

I know similar questions have been asked before, but I didn't find a solution in them.

解决方案

Unfortunately the only "safe" way to do it is to check the source code of FragmentPagerAdapter, and see what tag is the fragment is added with - because findFragmentByTag is the only safe way to get a Fragment from a FragmentManager.

Of course, we need to hope that this implementation detail doesn't change between support library versions, but it actually hasn't changed in years :)


Anyways, so FragmentPagerAdapter says:

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);

So what is name?

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

What is viewId and what is id?

ViewId is container.getId(), where container is the ViewPager itself.

id is: final long itemId = getItemId(position); which by default is return position;.


So you can find the Fragment as follows:

Fragment fragment = fragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition);
// if fragment is null, it was not created yet by ViewPager


NOTE:

It is worth noting that you should NOT rely on getItem(int position) { to return the same fragment instance as you passed in, because that will lead you to this problem. (This question does it correctly, the getItem() method must always return a new Fragment instance.)

相关文章