无法在 Viewpager 中获取当前视图

Posted

技术标签:

【中文标题】无法在 Viewpager 中获取当前视图【英文标题】:not able to get the current view in Viewpager 【发布时间】:2013-05-02 06:50:54 【问题描述】:

我正在使用 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);

现在我面临的问题是,在我滚动 3 页之后,当我来到第 4 页时,我在“myTextView = (TextView)currView.findViewById(R.id.myTextView);”这一行上得到空指针异常。这是因为 currView 为空。如果我在这里做错了任何想法。有没有其他方法可以在 viewpager 中捕获当前视图(页面),以便我可以根据我所在的页码对视图进行更改?

【问题讨论】:

我认为你应该在这里调试:mPager.getChildAt(mPager.getCurrentItem()); 为什么它返回 null? 使用此答案获取当前视图***.com/a/8638772/527759 @user527759:您共享的线程中的 sloution 适用于寻呼机适配器。但是,我正在使用 FragmentStatePagerAdapter。该方法将返回一个无法转换为查看的 Fragment 对象,因此建议的代码将不起作用 你可以保存当前片段并使用Fragment.getView() 尝试这样做,但由于我收到 classcast 异常而无法获取片段对象。 【参考方案1】:

您可以将 setTag 与您在 instantiateItem 方法 (PagerAdapter) 中返回的视图一起使用。

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

像这样:

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

当你需要当前视图时:

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

【讨论】:

不清楚决定,因为instantiateItem(...) 在Object 接口下返回Fragment。而且我们只有在提交事务后才能使用 Fragemnt.getView()。 在一个非常特殊的情况下 - 在 ViewPager.SimpleOnPageChangeListener 的 onPageSelected() 回调中,pager.findViewWithTag(my_tag) 可能会返回 null,因为在创建任何其他项目之前首先调用此回调。但是以下调用是可以的,因为视图寻呼机会在显示它们之前创建其他项目。【参考方案2】:

你使用这种方法:

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

【讨论】:

【参考方案3】:

由于您已将 offscreenPageLimit 设置为 3,因此您将获得空指针异常。viewpager 将仅存储 3 页。mPager.getChildAt(4) 将获得空值。 设置textview,可以使用adapter的fragment manager来获取所有fragment,并获取fragment所在位置的view。

adapter.fragmentManager.fragments[position1].view

【讨论】:

【参考方案4】:

我在我的适配器中添加了一个 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) 

)

【讨论】:

【参考方案5】:

您当前视图为空的原因是寻呼机适配器开始销毁其项目以提高内存效率。我发现一种可行的方法是覆盖寻呼机适配器的 destroyItem() 方法并通过列表或 parceable 类保存您的数据。

【讨论】:

以上是关于无法在 Viewpager 中获取当前视图的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助来修复在 viewpager 中获取当前视图的代码

如何让viewpager取消预加载且能有tabpageindicator

无法在 viewpager 上获取选定选项卡的位置

在drupal中获取当前页面视图

无法使用数据绑定绑定 viewpager2 数据

android:viewpager里如何获取其子界面的按钮并为其添加监听器啊?