【问题标题】:Get focused View from ViewPager从 ViewPager 获取焦点视图
【发布时间】:2011-10-12 01:04:04
【问题描述】:

我使用 ViewPager 通过左右滑动切换视图。

ViewPager 需要一个 Adapter,所以我构建了这个:

public class ListViewPagerAdapter extends PagerAdapter {

protected static final String TAG = "ListViewPagerAdapter";
protected static final int NUM_VIEWS = 3;

protected final Activity mActivity;

public ListViewPagerAdapter(Activity activity) {
    mActivity = activity;
}

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

@Override
public void startUpdate(View container) {}

@Override
public Object instantiateItem(View container, int position) {
    // ViewPager
    ViewPager viewPager = (ViewPager) container;

    // Wird verwendet, um die Views aufzurufen
    LayoutInflater layoutInflater = mActivity.getLayoutInflater();

    // Standardmäßig ist news eingeblendet
    View view = layoutInflater.inflate(R.layout.news_fragment, null);
    // Falls sich die Position verändert, so verändert sich auch die View
    if (position == 0) {
        view = layoutInflater.inflate(R.layout.favorite_fragment, null);
    } else if (position == 2) {
        view = layoutInflater.inflate(R.layout.videos_fragment, null);
    }

    // View einblenden
    viewPager.addView(view, 0);

    return view;
}

@Override
public void destroyItem(View container, int position, Object object) {
    // ViewPager
    ViewPager viewPager = (ViewPager) container;
    // View
    View view = (View) object;

    // View löschen
    viewPager.removeView(view);
}

@Override
public void finishUpdate(View container) {}

@Override
public boolean isViewFromObject(View view, Object object) {
    View _view = (View) object;
    return view == _view;
}

@Override
public Parcelable saveState() {
    return null;
}

@Override
public void restoreState(Parcelable state, ClassLoader loader) {}
 }

现在,我想通过 viewpager 获取当前的焦点视图。 我尝试了 getChildAt(x),但它不起作用。

有没有一些例子,或者你知道如何获得当前视图?

谢谢

【问题讨论】:

    标签: android view pager android-viewpager viewpage


    【解决方案1】:

    可以通过覆盖PagerAdapter.setPrimaryItem 方法来保存当前活动的对象(视图、片段...)。例如:

    private View mCurrentView;
    
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        mCurrentView = (View)object;
    }
    

    【讨论】:

    • 令人遗憾的是,当前的可见项实现未内置在寻呼机适配器中。精彩的回答,谢谢。
    • 完美,这也是我在寻找的......这真的很奇怪!非常感谢!
    • 注意:该方法在页面滑动时被多次调用
    • 该方法似乎已弃用。
    • @osayilgan,它没有被弃用。不推荐使用的函数是另一个:setPrimaryItem (View container, int position, Object object)
    【解决方案2】:

    你必须为你的ViewPager注册一个监听器:

    pager.setOnPageChangeListener(new MyPageChangeListener()); 
    

    您必须通过扩展存根侦听器来自定义侦听器:

    private int focusedPage = 0;
    private class MyPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
        @Override
        public void onPageSelected(int position) {
            focusedPage = position;
        }
    }
    

    我通过查看 compatibility library 中的 ViewPager.java 源代码发现了这一点。我读到我们可以做更多,例如 catch onPageScrollStateChanged

    为了构建适配器,我使用了代码on this blog post。你可能想看看。

    【讨论】:

    • 我知道这如何让您获得当前位置,但我不清楚您如何从中获得当前视图。
    • 请注意,如果您将 ViewPagerIndicator 与 ViewPager 结合使用,则必须在指示器上设置侦听器,而不是在寻呼机上。
    • @JoeRegan 我能够从ViewPager 上的getChildAt(int) 获得当前视图,这是我从OnPageChangeListener 获得的最后一个已知位置。
    • Yuriy 的评论是完全正确的:如果您想在寻呼机中使用超过 3 次查看的解决方案,您需要在寻呼机上调用 setOffscreenPageLimit 并将查看次数传递给它
    【解决方案3】:

    你可以在instanceiteItem方法中为创建的视图添加标签:

    view.setTag(position);
    

    稍后您可以通过以下方式访问当前选定的视图:

    mPager.findViewWithTag(mPager.getCurrentItem());
    

    【讨论】:

    • 我认为这是最简单的方法。非常感谢。
    • 好的,但是你应该保存原始标签,然后再恢复它。
    • view 是返回的对象,如return view
    【解决方案4】:

    我最近需要实施这个确切的解决方案。这是我的做法:

    Map<Integer, Object> views = Maps.newHashMap();
    
    @Override
    public Object instantiateItem(View container, int position) {
      /* Create and add your View here */
      Object result = ???
    
      views.put(position, result);
      return result;
    }
    
    @Override
    public void destroyItem(View container, int position, Object object) {
      /** Remove your View here */
    
      views.remove(position);
    }
    
    protected View findViewForPosition(int position) {
      Object object = views.get(position);
      if (object != null) {
        for (int i = 0; i < getChildCount(); i++) {
          View view = getChildAt(i);
          if (isViewFromObject(view, object)) {
            return view;
          }
        }
      }
      return null;
    }
    

    【讨论】:

    • 这对我有用,谢谢!但是在您的findViewForPosition(int) 方法中,为什么要遍历孩子并调用isViewFromObject(View,Object)?我已经简单地将这个方法实现为return views.get(position); 并且还没有遇到任何问题。
    • 因为无法保证以任何特定顺序将子项添加到容器中。 PagerAdapter API 还允许返回任意对象引用,这不一定是视图。我在示例中犯了一个错误,地图应该是 Map
    • 仍然,这不会给你当前显示或聚焦的视图,因为在上面的函数中我需要传递一个位置,也就是说很难获得值,即当前定位的视图,如果我本可以得到这个位置,我 cud 直接使用了 getChildAt(x) 而不是 this..getCurrentItem() 从数据集中返回索引。
    【解决方案5】:

    试试这个:

    public View getCurrentView(ViewPager pager) {
        for (int i = 0; i < pager.getChildCount(); i++) {
            View child = pager.getChildAt(i);
            if (child.getX() <= pager.getScrollX() + pager.getWidth() && 
                child.getX() + child.getWidth() >= pager.getScrollX() + pager.getWidth()) {
                return child;
             }
         }
         return getChildAt(0);
    }
    

    【讨论】:

    • 并非如此。适用于少数视图。当我向后滚动时,视图失败。
    • @user1938357:这是因为适配器删除了视图以释放内存。
    【解决方案6】:

    为了获得焦点视图,我使用这种方式:

    当我在将视图添加到 ViewPager 之前膨胀视图时,我为其设置了标签。然后我检查这个标签。

    private View getCurrentView()
    {
        for (int i = 0; i < pager.getChildCount(); i++)
        {
            View v = pager.getChildAt(i);
            if (v != null)
            {
                if (v.getTag().equals(pageList.get(pager.getCurrentItem()).getTag())) return v;
                // pageList is a list of pages that I pass to page adapter
            }
        }
        return null;
    }
    

    【讨论】:

    • 你在这里匹配的标签值是什么?其次,你在哪里设置 pageList 中的标签值?好像我尝试设置它 intantiateItem 方法,但同样基于视图位置而不是 pageList 中的实际数据对象索引?
    【解决方案7】:

    给定的答案并不适合我,它们都有不想要的副作用。要么我必须添加不必要的变量(我喜欢干净的代码),要么我必须解决 Android 框架本身。

    我的解决方案是基于反射的,它访问ViewPager中所有对象的数组列表,并返回ViewPager中当前选中的对象。它几乎没有副作用(反射很慢,是现有类的子类化),并且保持代码干净。

    public class ViewPagerEx extends ViewPager {
    
        private static final String TAG = ViewPagerEx.class.getSimpleName();
    
        public ViewPagerEx(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public ViewPagerEx(Context context) {
            super(context);
        }
    
        public Object getCurrentObject() {
            try {
                final Field itemsField = ViewPager.class.getDeclaredField("mItems");
                itemsField.setAccessible(true);
    
                final ArrayList<Object> items = (ArrayList<Object>) itemsField.get(this);
    
                final int currentItemIndex = getCurrentItem();
                if (currentItemIndex < 0 || currentItemIndex >= items.size()) {
                    return null;
                }
    
                final Object infoItem = items.get(getCurrentItem());
    
                final Class<?> itemInfoClass = findItemInfoClass(ViewPager.class.getDeclaredClasses());
    
                final Field objectField = itemInfoClass.getDeclaredField("object");
                objectField.setAccessible(true);
                return objectField.get(infoItem);
    
            } catch (NoSuchFieldException e) {
                Log.e(TAG, e.toString());
            } catch (IllegalArgumentException e) {
                Log.e(TAG, e.toString());
            } catch (IllegalAccessException e) {
                Log.e(TAG, e.toString());
            }
    
            return null;
        }
    
        private Class<?> findItemInfoClass(final Class<?>[] classes) throws IllegalArgumentException {
            for (int i = 0; i < classes.length; i++) {
                if (classes[i].getSimpleName().equals("ItemInfo")) {
                    return classes[i];
                }
            }
    
            throw new IllegalArgumentException("cannot find class ItemInfo");
        }
    }
    

    【讨论】:

      【解决方案8】:

      在你的FragmentStatePagerAdapter

          private View mCurrentView;
      
          @Override
          public void setPrimaryItem(ViewGroup container, int position, Object object) {
              Fragment f = (Fragment) object;
              mCurrentView = f.getView();
          }
      

      【讨论】:

        【解决方案9】:

        你可以使用:

         viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        
                }
        
                @Override
                public void onPageSelected(int position) {
                    Log.i("maylonsales", "onPageSelected position " + position);
                }
        
                @Override
                public void onPageScrollStateChanged(int state) {
        
                }
            });
        

        【讨论】:

          【解决方案10】:

          如果仔细检查,ViewPager 最多保存 3 个视图。 您可以通过

          轻松获取当前视图
          view     = MyActivity.mViewPager.getChildAt(1);
          

          【讨论】:

          • 我注意到 ViewPager 最多保存了 4 个视图,当您查看分页器中的第一个或最后一个视图时,它只有 3 个。
          • 啊,这是因为我有一个标题栏。无论如何,在查看第一个和最后一个时,它在寻呼机中的 2 个视图
          【解决方案11】:

          我错过了什么吗? ViewGroup 中只有 3 个孩子,所以归结为:

          int current = viewPager.getCurrentItem();
          int childCount = viewPager.getChildCount();
          // If there's a single page or we're at the beginning, return the first view
          if (childCount == 1 || current == 0) {
            return viewPager.getChildAt(0);
          } else { //For any other case, we want the second child. This is either the last page or the page in the middle for any other case.
            return viewPager.getChildAt(1);
          }
          

          【讨论】:

          • 如果只有三个项目(除非你使用 setOffscreenPageLimit 来扩展它),viewPager.getChildAt(1) 将只当前中间项目,因为最后一个项目的索引为 2。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-22
          • 1970-01-01
          • 2016-04-15
          相关资源
          最近更新 更多