2011-12-21 190 views
69

我有一个应用程序ViewPager和三个Fragment s。我试图弄清楚如何获取当前的Fragment,以便我可以了解它的论点。是否可以访问ViewPager正在查看的当前片段?

我有一个OnPageChangeListener抓住当前页面的索引,但

ViewPager.getChildAt(int position); 

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

回答

46

我终于找到an answer为我工作。基本上,您可以通过使用标记“android:switcher:”+ R.id.viewpager +“:0”来访问viewPager页面的片段。

+27

链接答案中的方法不适用于FragmentStatePagerAdapter,但对同一链接问题的[第二个答案](http://stackoverflow.com/a/8886019/237820)有一个方法。 – 2012-08-06 21:59:38

+4

虽然这可能在理论上回答这个问题,但[这将是更可取的](http://meta.stackoverflow.com/q/8259)在这里包括答案的重要部分,并提供供参考的链接。 – Keelan 2015-04-15 19:37:56

1

它已经在这里解释:http://developer.android.com/guide/topics/fundamentals/fragments.html

在OnCreateView必须返回一个视图中绘制一个用户界面为你的片段,我认为这是关系。

而且这个问题可能是相似的:Get focused View from ViewPager

+0

嗨但丁,是的,我明白,但我试图得到的片段,鉴于视图。 – MitchellSalad 2011-12-21 18:03:05

+0

好的,getFragmentManager()。findFragmentById(R.id.fragment_container);'then?你会得到我认为在那个容器中的当前片段。 – Dante 2011-12-21 21:14:21

+1

找到此页面是因为我遇到同样的问题。 findFragmentById不适合我。 – James 2011-12-23 02:57:01

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; 
    }  
5

编辑 - 不要这样做。如果你有兴趣,请阅读评论为什么这是一个坏主意。

在奇数的机会,你还在试图解决这个问题:

扩展FragmentPagerAdapter。在构造函数中,构建您需要的Fragments,并将它们存储在Fragments的List(array/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]; 
} 

我不知道这是否是做它的普遍接受的方式,但它为我工作。

编辑

这实在是不走的好方法。如果您打算处理方向更改或您的应用进入后台,那么这可能会破坏您的代码。请阅读下面的评论以获取更多信息。相反使用@詹姆斯的回答

+0

如果预先创建每个片段不是反对,您的解决方案就没有问题。不要低估你的片段的成本。 – Rene 2013-02-27 13:44:01

+1

好点。当活动重新启动时,我也遇到了这种方式的问题,并且碎片的getActivity()不返回当前的活动,但之前的一些已被销毁的实例 – 2013-02-28 05:53:32

+2

直到您旋转设备为止。然后片段将在旋转中生存下来,但您的适配器的缓存不会。现在,当您询问当前显示的片段时,您将创建一个根本不使用的新片段。 – 2013-03-05 09:33:18

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

MyActivity:

public class MyActivity implements IMyActivity{ 

    [...] 

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

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

} 
+1

一旦你注册了你的片段,你如何通过它的位置找到它? – 2015-07-09 23:16:06

3

请勿使用本

让您的适配器扩展以下FragmentStatePagerWithCurrentAdapter类,而不是实施getItem实现相同的代码到getItemAtIndex

设置ViewPagerOnPageChangeListener,在适配器的实例。

当您需要访问当前的片段时,您只需拨打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

+2

这是不对的。在设备轮换的情况下,系统将通过调用片段的构造函数而不通过PagerAdapter.getItem来重新创建片段。唯一可行的选择是将片段对象保存在Fragment.onAttach中,如sdl shows。 – 2014-11-26 20:50:40

+0

@StephenCheng你是对的。当我使用这个应用程序时,我有一个固定的肖像应用程序,但是随后发现了当由于内存压力而导致活动中断并且状态被重新加载时您提到的问题。我最终将这些代码重写为一个更复杂的代码,以处理我们所需的所有场景,包括这个场景。 – 2014-11-27 21:13:44

0

Jorge Garcia's 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被称为每次在该位置的片段被访问时以下。

-2

我认为有更好的办法利用这个

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

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

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,如果存在:

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

或者只需保存的所有片段在地图:

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

    } 

} 
5

是的,这是可能的,如果你正在使用FragmentStatePagerAdapter

ViewPager vp; 
//... 
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem()); 
相关问题