使用RecyclerView + ViewPager 实现轮播广告的两个Bug

大家都知道,RecyclerView没有addHeaderView的方法,所以,要实现添加头部,就需要在RecyclerAdapter中进行。

ViewPager作为RecyclerView的其中一项
过程中发现两个问题:

1.当ViewPager不可见时,会执行其onDetachedFromWindow方法,再次可见时会执行onAttachedToWindow方法。

  • 在Android4.0上会出现第一次自动滑动没有动画效果。
  • 在Android5.0上会出现第一次滑动不仅没有动画效果,而且连View都没有。

2.当ViewPager自动滑动到一半的时候,将其隐藏后,无法自动滑完。会出现滑一半的情况。

这里写图片描述

这里写图片描述

第一个问题

原因

根据源码可以看出是mFirstLayout的问题

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    //这是自动将mFirstLayout设置为了true
    mFirstLayout = true;
}

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
    if (mAdapter == null || mAdapter.getCount() <= 0) {
        setScrollingCacheEnabled(false);
        return;
    }
    if (!always && mCurItem == item && mItems.size() != 0) {
        setScrollingCacheEnabled(false);
        return;
    }

    if (item < 0) {
        item = 0;
    } else if (item >= mAdapter.getCount()) {
        item = mAdapter.getCount() - 1;
    }
    final int pageLimit = mOffscreenPageLimit;
    if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
        // We are doing a jump by more than one page.  To avoid
        // glitches, we want to keep all current pages in the view
        // until the scroll ends.
        for (int i=0; i<mItems.size(); i++) {
            mItems.get(i).scrolling = true;
        }
    }
    final boolean dispatchSelected = mCurItem != item;

    //这里根据mFirstLayout判断选择ViewPager在切换页面时的效果
    //由此可以看出,当ViewPager隐藏后再次显示时,走的是第一步,没有动画效果
    //并且会导致5.0以上的系统出现更多的bug
    if (mFirstLayout) {
        // We don't have any idea how big we are yet and shouldn't have any pages either.
        // Just set things up and let the pending layout handle things.
        mCurItem = item;
        if (dispatchSelected) {
            dispatchOnPageSelected(item);
        }
        requestLayout();
    } else {
        populate(item);
        scrollToItem(item, smoothScroll, velocity, dispatchSelected);
    }
}

解决方法:

自定义ViewPager,在onAttachedToWindow中将mFirstLayout设置为false,但是mFirstLayout是私有变量,所以必须用到反射

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    /**
     * 坑,解决在RecyclerView中使用的bug
     * 设ViewPager中有3张照片
     * 当ViewPager滑动一遍之后,向下滑动RecyclerView列表
     * 直到完全隐藏此ViewPager,并执行了onDetachedFromWindow
     * 再回来时,将会出现bug,第一次滑动时没有动画效果,并且,经常出现view没有加载的情况
     */
    try {
        Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
        mFirstLayout.setAccessible(true);
        mFirstLayout.set(this, false);
        adapter.notifyDataSetChanged();
        setCurrentItem(getCurrentItem());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这里写图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值