【问题标题】:Is it possible to access the current Fragment being viewed by a ViewPager?是否可以访问 ViewPager 正在查看的当前 Fragment?
【发布时间】:2011-12-21 08:54:51
【问题描述】:

我有一个带有ViewPager 和三个Fragments 的应用程序。我正在尝试弄清楚如何查看当前的Fragment,以便了解它的论点。

我有一个OnPageChangeListener 获取当前页面索引,但是

ViewPager.getChildAt(int position);

返回View。这个View和现在的Fragment是什么关系?

【问题讨论】:

    标签: android android-fragments android-viewpager


    【解决方案1】:

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

    【讨论】:

    • 链接答案中的方法不适用于 FragmentStatePagerAdapter,但同一链接问题的 second answer 有一个方法可以。
    • 虽然这在理论上可以回答问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
    【解决方案2】:

    我已经反过来解决了这个问题。 我不是从活动中搜索片段,而是在其所有者活动的 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);
        }
    
    }
    

    【讨论】:

    • 一旦你注册了你的片段,你如何通过它的位置找到它?
    • 这不起作用,因为OnAttach 没有被调用,如果你折叠你的活动,而OnStop 仍然被调用。
    【解决方案3】:

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

    如果你仍然在尝试解决这个问题:

    扩展FragmentPagerAdapter。在构造函数中,构建您需要的片段并将它们存储在片段的列表(数组/数组列表)中。

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

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

    编辑

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

    【讨论】:

    • 如果不反对预先创建每个片段,您的解决方案就很好。不过不要低估碎片的成本。
    • 好点。当 Activity 重新启动时,我也遇到了这样的问题,并且 Fragments 的getActivity() 不会返回当前的活动,而是一些先前的实例已被破坏
    • 这在您旋转设备之前有效。然后片段将在旋转中幸存下来,但您的适配器的缓存不会。现在,当您请求当前显示的片段时,您将创建一个根本不使用的新片段。
    • 同意。我不认为这是一个很好的方法,因为我已经学到了更多。许多应用程序会锁定屏幕方向(例如游戏),但即便如此,如果应用程序进入后台然后返回,我认为也会发生同样的问题。
    • @RolfSmit:我同意。我只是将其保留,以便人们阅读讨论,并可能为锁定屏幕方向的人阅读
    【解决方案4】:

    是的,如果您使用的是FragmentStatePagerAdapter,这是可能的。

    ViewPager vp;
    //...
    YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());
    

    【讨论】:

      【解决方案5】:

      请不要使用这个

      让您的适配器扩展以下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

      【讨论】:

      • 这是不对的。在设备旋转的情况下,系统将通过调用片段的构造函数来重新创建片段,而无需通过 PagerAdapter.getItem。唯一可行的选择是将片段对象保存在 Fragment.onAttach 中,就像 sdl 显示的那样。
      • @StephenCheng 你是对的。当我使用它时,我有一个固定的肖像应用程序,但后来发现了你提到的问题,当活动由于内存压力而被杀死然后状态被重新加载时。我最终将这段代码重写为更复杂的代码,以处理我们需要的所有场景,包括这个。
      【解决方案6】:

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

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

      这个问题也可能类似:Get focused View from ViewPager

      【讨论】:

      • 嗨但丁,是的,我明白这一点,但鉴于视图,我正在尝试获取片段。
      • 好的,那getFragmentManager().findFragmentById(R.id.fragment_container); 呢?我认为您会在该容器中获得当前片段。
      • 找到这个页面是因为我有同样的问题。 findFragmentById 对我不起作用。
      【解决方案7】:

      您可以这样做: - 在视图分页适配器(例如 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;
          }    
      

      【讨论】:

        【解决方案8】:

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

        页面片段布局中的某处:

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

        【讨论】:

          【解决方案9】:

          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。

          【讨论】:

            【解决方案10】:

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

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

            【讨论】:

              【解决方案11】:

              我认为使用这个有更好的方法

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-07
                • 2019-03-15
                • 2018-03-28
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多