无法获取Viewpager中的当前视图

20

我正在使用ViewPager来跨多个页面展示一些文本。我试图在选择新页面时获取当前视图。我需要获取当前视图的原因是因为根据页面编号我要改变一些视图组件(如textview、image)的属性。 我正在使用以下代码实现:

ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
View CurrView;
OnPageChangeListener pageChangelistener = new OnPageChangeListener() {
  @Override
       public void onPageSelected(int pageSelected) {
          currView = mPager.getChildAt(mPager.getCurrentItem());
      myTextView = (TextView)currView.findViewById(R.id.myTextView);
              loadBookmarkSetting(pageSelected);//do some changes in myTextView    properties based on the page number  }
 mPager.setOnPageChangeListener(pageChangelistener);

现在我面临的问题是,当我滚动三页后到第四页时,我会在这行代码"myTextView =(TextView) currView.findViewById(R.id.myTextView);"上得到NullPointerException。这是因为currView为空。我是否做错了什么?是否有其他方法可以捕获viewpager中的当前视图(页面),以便我可以根据页码对视图进行更改?


我认为你应该在这里调试:mPager.getChildAt(mPager.getCurrentItem()); 为什么它返回 null? - MysticMagicϡ
2
使用此答案获取当前视图 https://dev59.com/c2w15IYBdhLWcg3wIoRM#8638772 - Eugene Popovich
@user527759:你分享的线程中的解决方案适用于 PagerAdapter。但我正在使用 FragmentStatePagerAdapter。那种方法会返回一个 Fragment 对象,无法转换为 View,因此建议的代码将无法运行。 - user1938357
你可以保存当前片段并使用Fragment.getView() - Eugene Popovich
尝试过这样做,但无法获取片段对象,因为我收到了类转换异常。 - user1938357
可能是重复的问题:Android ViewPager get the current View - Boris Strandjev
5个回答

66

你可以在你的 instantiateItem 方法(PagerAdapter)中返回的视图上使用 setTag。

因此,在 PagerAdapter 中实例化视图时,该方法也是 instantiateItem(ViewGroup container, int position)),你应该对你的视图使用 setTag。

像这样:

view.setTag("myview" + position);
return view;

当您需要当前视图时:

View view = (View) pager.findViewWithTag("myview" + pager.getCurrentItem());

3
决策不明确,因为instantiateItem(...)返回Object接口下的Fragment。而我们只能在提交事务后使用Fragment.getView()。 - ultraon
在一个非常特殊的情况下 - 在ViewPager.SimpleOnPageChangeListener的onPageSelected()回调函数内,pager.findViewWithTag(my_tag)可能会返回null,因为此回调函数首先被调用,而其他项尚未创建。但是随后的调用是可以的,因为视图分页器将在显示它们之前创建其他项。 - StoneLam

4
您使用的是这种方法:
@Nullable
    public static View getActiveView(@Nonnull final ViewPager viewPager) {
        final PagerAdapter adapter = viewPager.getAdapter();
        if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
            return null;
        }

        int position;
        final int currentPosition = viewPager.getCurrentItem();

        for (int i = 0; i < viewPager.getChildCount(); i++) {
            final View child = viewPager.getChildAt(i);
            final LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            if (layoutParams.isDecor) {
                continue;
            }
            final Field positionField;
            try {
                positionField = LayoutParams.class.getDeclaredField("position");
                positionField.setAccessible(true);
                position = positionField.getInt(layoutParams);
            } catch (NoSuchFieldException e) {
                break;
            } catch (IllegalAccessException e) {
                break;
            }
            if (position == currentPosition) {
                return child;
            }
        }
        return null;
    }

1
您之所以出现空指针异常,是因为您将offscreenPageLimit设置为3。ViewPager仅存储3个页面。mPager.getChildAt(4)将获取一个null。 要设置TextView,可以使用适配器的片段管理器获取所有片段,然后获取位置处片段的视图。
adapter.fragmentManager.fragments[position1].view

0

我在适配器中添加了一个SparseArray,并在instantiateItem()中添加视图,在destroyItem()中删除它。

val views = SparseArray<View>()

...

override fun instantiateItem(container: ViewGroup, position: Int): Any 
{
    //...

    container.addView(view)
    views.put(position, view)
    return view
}

override fun destroyItem(container: ViewGroup, position: Int, obj: Any) 
{
    views.remove(position)
    container.removeView(obj as View)
}

fun showFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(1f)
}

fun hideFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(0f)
}

然后我可以在适配器上调用方法:

viewPager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener {
    override fun onPageScrollStateChanged(state: Int) {
        when (state) {
            SCROLL_STATE_IDLE -> adapter.showFooter(viewPager.currentItem)
            SCROLL_STATE_DRAGGING -> adapter.hideFooter(viewPager.currentItem)
        }
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

    override fun onPageSelected(position: Int) {}

})

-1
你当前视图为空的原因是,为了提高内存效率,pager adapter开始销毁其项目。我发现的一种方法是重写 pager adapter 的 destroyItem() 方法,并通过列表或可序列化类来保存数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接