是否可以访问ViewPager正在查看的当前片段?


70

我有一个带有aViewPager和3 Fragments的应用程序。我正在尝试弄清楚如何Fragment查看当前内容,以便了解其参数。

我正在OnPageChangeListener抓取当前页面索引,但是

ViewPager.getChildAt(int position);

返回View。这View和当前之间有什么关系Fragment

Answers:


46

我终于找到对我有用的答案。基本上,您可以使用标签“ android:switcher:“ + R.id.viewpager +”:0“访问viewPager页面的片段。


27
链接答案中的方法不适用于FragmentStatePagerAdapter,但是同一链接问题的第二个答案中的方法可以。
亚当·L.

4
尽管从理论上讲这可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。

18

我已经反过来解决了这个问题。我没有从活动中搜索片段,而是在其所有者活动的onAttach()方法期间注册了该片段,并在onStop()方法中将其取消了注册。基本思路:

分段:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try{
        mActivity = (IMyActivity)activity;
    }catch(ClassCastException e){
        throw new ClassCastException(activity.toString() +" must be a IMyActivity");
    }

    mActivity.addFragment(this);
}

@Override
public void onStop() {
    mActivity.removeFragment(this);
    super.onStop();
}

IMyActivity:

public interface IFriendActivity {
    public void addFragment(Fragment f);
    public void removeFragment(Fragment f); 
}

我的活动:

public class MyActivity implements IMyActivity{

    [...]

    @Override
    public void addFragment(Fragment f) {
        mFragments.add(f);
    }

    @Override
    public void removeFragment(Fragment f) {
        mFragments.remove(f);
    }

}

2
注册片段后,如何通过其位置找到它?
肖恩·劳松

这是行不通的,因为OnAttach未调用是在您OnStop仍处于调用状态时折叠活动。
Mike Keskinov

5

编辑-不要这样做。如果您很想这样做,请阅读注释,了解为什么这是一个坏主意。

在奇怪的机会上,您仍在尝试解决此问题:

扩展FragmentPagerAdapter。在构造函数中,构建所需的片段,并将其存储在片段列表(数组/ ArrayList)中。

private final int numItems = 3;
Fragment[] frags;

public SwipeAdapter (FragmentManager fm) {
    super(fm);

    //Instantiate the Fragments
    frags = new Fragment[numItems];

    Bundle args = new Bundle();
    args.putString("arg1", "foo");

    frags[0] = new MyFragment();
    frags[1] = new YourFragment();
    frags[2] = new OurFragment();
    frags[2].setArguments(args);
}

然后getItem(int position),您可以执行类似

public Fragment getItem(int position) {
    return frags[position];
}

我不确定这是否是普遍接受的方式,但对我有用。

编辑

这确实不是一个好方法。如果您打算处理方向更改或您的应用程序进入后台,那么这很可能会破坏您的代码。请阅读此答案下方的评论以获取更多信息。宁可使用@James的答案


1
如果预先创建每个片段都不反对,那么您的解决方案就很好。不要低估片段的成本。
Rene

2
好点子。当“活动”重新启动时,我也遇到了这样的问题,“碎片”getActivity()不会返回当前活动,但是某些先前的实例已被销毁
Mike T

4
在旋转设备之前,此方法一直有效。这样,片段将在旋转中幸存下来,但适配器的缓存将无法保存。现在,当您请求当前显示的片段时,您将创建一个根本不使用的新片段。
MarkGjøl13年

2
同意 我已经学到了更多的知识,所以我认为这不是一个好方法。许多应用都锁定屏幕方向(例如游戏),但是即使那样,如果应用转到后台然后又返回,我认为也会发生相同的问题。
Mike T

3
@RolfSmit:我同意。我只是将其保留下来,以便人们阅读讨论,并可能适合锁定屏幕方向的人们
Mike T


3

请不要使用这个

使您的适配器扩展以下FragmentStatePagerWithCurrentAdapter类,而不是实现getItem将相同的代码实现为getItemAtIndex

将设置ViewPager OnPageChangeListener为适配器的实例。

当您需要访问当前的Fragment时,只需调用adapter.getCurrentItem()

package your.package;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.SparseArray;
import android.view.ViewGroup;

public abstract class FragmentStatePagerWithCurrentAdapter 
extends FragmentStatePagerAdapter 
implements OnPageChangeListener {
    int currentPage = 0;

    private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();

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

    @Override
    public final Fragment getItem(int index) {
        Fragment myFragment = getItemAtIndex(index);
        mPageReferenceMap.put(index, myFragment);
        return myFragment;
    }

    public abstract Fragment getItemAtIndex(int index);

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {

        super.destroyItem(container, position, object);

        mPageReferenceMap.remove(Integer.valueOf(position));
    }

    public Fragment getCurrentItem() {
        return mPageReferenceMap.get(currentPage);
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {

    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }

    @Override
    public void onPageSelected(int newPageIndex) {
        currentPage = newPageIndex;
    }

}

我将以下博客文章用作参考:http : //tamsler.blogspot.com/2011/11/android-viewpager-and-fragments-part-ii.html


3
这个不对。在设备旋转的情况下,系统将通过调用片段的构造函数来重新创建片段,而无需通过PagerAdapter.getItem。唯一可行的选择是像sdl所示将片段对象保存在Fragment.onAttach中。
Stephen Cheng

@StephenCheng你是对的。使用此工具时,我有一个固定的纵向应用程序,但后来发现由于内存压力而导致活动被杀死,然后重新加载状态时,您提到的问题。我最终将这段代码重写为一个复杂得多的代码,以处理我们需要的所有场景,包括此场景。
豪尔赫·加西亚

1

在这里进行了解释:http : //developer.android.com/guide/topics/fundamentals/fragments.html

在OnCreateView中,您必须返回一个视图以为片段绘制UI,我认为这就是关系。

这个问题也可能是类似的:从ViewPager获取焦点视图


嗨,但丁,是的,我理解这一点,但鉴于视图,我正在尝试获取片段。
米切尔·

好吧getFragmentManager().findFragmentById(R.id.fragment_container);那怎么办 我认为您将在该容器中获得当前片段。
但丁

1
找到此页面,因为我有同样的问题。findFragmentById对我不起作用。
詹姆斯

1

您可以这样做:-在视图分页器适配器的类范围内(例如PagerAdapter,FragmentStatePagerAdapter ...),重写方法InstantiateItem:

@Override
public Object instantiateItem(ViewGroup container, int position) {
        final Fragment frag = (Fragment) super.instantiateItem(container, position);
        if(frag instanceof ListNoteOfTypeFragment){                
            final ListNoteOfTypeFragment listNoteOfTypeFragment = (ListNoteOfTypeFragment) frag;
            //do whatever you want with your fragment here
            listNoteOfTypeFragment.setNoteChangeListener(mListener);
        }
        return frag;
    }    

1

可以无缝运行的确定性答案(但小技巧):

页面片段布局中的某处:

<FrameLayout android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone" android:id="@+id/fragment_reference">
     <View android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone"/>
</FrameLayout>

在片段的onCreateView()中:

...
View root = inflater.inflate(R.layout.fragment_page, container, false);
ViewGroup ref = (ViewGroup)root.findViewById(R.id.fragment_reference);
ref.setTag(this);
ref.getChildAt(0).setTag("fragment:" + pageIndex);
return root;

和从ViewPager返回Fragment的方法(如果存在):

public Fragment getFragment(int pageIndex) {        
        View w = mViewPager.findViewWithTag("fragment:" + pageIndex);
        if (w == null) return null;
        View r = (View) w.getParent();
        return (Fragment) r.getTag();
}

0

豪尔赫·加西亚(Jorge Garcia)的FragmentStatePagerWithCurrentAdapter是一个很好的解决方案,但还需要一点改进。如果活动因响应配置更改而销毁并重新创建,或者类似的事件,则不会为片段管理器保存和检索的片段调用getItem。所以我通常在子类中重写getItem,然后将以下内容放入FragmentStatePagerWithCurrentAdapter中

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object item = super.instantiateItem(container, position);
    if ( item instanceof Fragment ) {
        pageReferenceMap.put(position, (Fragment)item);
    }
    return item;
}

每次访问该位置的片段时,都会调用InstantiateItem。


0

或者只是将所有片段保存在地图中:

public class MyFragment extends Fragment implements OnPageChangeListener {

    private ViewPager viewPager;
    private FragmentStatePagerAdapter viewAdapter;
    private View rootView;
    private Map<Integer, Fragment> fragments = new HashMap<Integer, Fragment>();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.introdution, container, false);

        viewPager = (ViewPager) rootView.findViewById(R.id.pager);
        viewAdapter = new ViewAdapter(getFragmentManager());
        viewPager.setAdapter(viewAdapter);
        viewPager.addOnPageChangeListener(this);

        return rootView;

    }

    private class ViewAdapter extends FragmentStatePagerAdapter {

        public ViewAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        @Override
        public Fragment getItem(int position) {

            Fragment result = null;

            switch (position) {
                case 0: result = Fragment1.newInstance(); break;
                case 1: result = Fragment2.newInstance(); break;
            }

            if (result != null)
                fragments.put(position, result);

            return result;

        }

        @Override
        public int getCount() {

            return 2;
        }

    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    }

    @Override
    public void onPageSelected(int position) {

        Fragment currentFragment = fragments.get(position);

    }

}

-2

我认为有更好的方法

Log.i(TAG, "getCurrentItem " + mViewPager.getCurrentItem());

可以获得当前的显示片段页面。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.