ViewCompat.offsetTopAndBottom翻车现场

引言

去年我开源了一个RecyclerView吸顶库,关于它的介绍请大家移步“我开源了一个RecyclerView吸顶库”一文。别看这个库大量使用了泛型,对象池、链表等技术,但是吸顶的功能真正倚仗的只有ViewCompat.offsetTopAndBottom(View view,int offset)这一个方法。它能够帮我们实现将View上下平移。它的姐妹方法offsetLeftAndRight(View view, int offset)可以实现将View左右平移,一般情况使用它们实现平移效果非常简单,适合各种阶段的Android开发者使用,堪称老少咸宜,效果那是童叟无欺。但是在我的吸顶库中,偏偏在某些特殊的情况下,调用了offsetTopAndBottom方法,View并没有发生预期的偏移效果,而是呆呆的停留在原地,我靠,翻车了!本来想从源码的角度正面寻找这个问题的答案,奈何offsetTopAndBottom虽然使用简单,但是源码一点都不简单。正面攻破不了,能否有办法从侧面解决呢?下面我将还原一下翻车现场,以及几个侧面解决的方案。

吸顶库github地址,欢迎star,欢迎和我一起维护这个项目。
https://github.com/lizijin/StickyHeaderForRecyclerView

还原翻车现场


这是来自我吸顶库中的一段代码,这里有翻车现场,如果你看不懂,也没关系,后面我会用一个非常简单的例子来还原这个现场。这段代码的功能是处理向下滑动RecyclerView时,切换吸顶功能。我们注意到addStickyView(newStickyView)方法将newStickyView视图添加到mStickyHeaderLayout布局中,紧接着调用ViewCompat.offsetTopAndBottom(mStickyHeaderLayout, mStickyHeaderLayoutTop - mStickyHeaderLayout.getMeasuredHeight() - mStickyHeaderLayout.getTop()),想要实现的效果是将mStickyHeaderLayout隐藏掉。问题就在于mStickyHeaderLayout此刻并没有隐藏掉,而是岿然不动的停留在原来的位置。所以在手机上的效果是,向下滑动RecyclerView时,当发生吸顶切换时,会有一个让人非常不适的闪动效果,当时出现这个问题时,我的内心肯定是在骂人的了,极度不理解,为啥调用了offset方法,确没有发生偏移呢,如果不解决这个问题,那么之前在该库上花的心血几乎要功亏一篑了。没办法,只能擦干眼泪找原因,找解决方案了。首先一个非常值得怀疑的点是,是不是因为先调用了addView 再调用offset方法,导致失效了呢?写个DEMO来验证一下。

DEMO还原现场

上面吸顶库的代码比较复杂,那我来写个简单的DEMO验证一下上面的疑问。代码我已上传至github,https://github.com/lizijin/zijiexiaozhan

布局文件

验证offset问题的Demo

上述代码,模拟了在吸顶库中遇到的问题,在addView后立马调用offset,点击“ADD AND OFFSET”按钮效果如下,仅仅是把newButton添加到屏幕中,并没有向下平移100像素。

解决问题

已经还原了问题现场,下一步就是定位问题和解决问题了。熟悉View.post(Runnable action)技巧的同学可能会第一时间想到用View.post来解决这个问题。我的第一反应也是这么想的。于是信手拈来,加个post。

1.1 使用post方式解决

post方式解决

1.2 效果

能够完美的解决不偏移的问题,但是引入了新问题,真机上可以明显看到闪烁。gif图由于分辨率的问题,看不出闪烁

2.1 使用post方式+setAlpha解决

既然有闪烁,于是我思索了好久,如何能解决这种肉眼可见的闪烁bug呢?突然有一天,灵光一现,能否在偏移前后,设置它的透明度呢?post之前setAlpha(0),post时setAlpha(1),于是尝试一番,果不其然能够解决闪烁的问题。
post+setAlpha方式解决

2.2 效果

能够完美的解决不偏移和闪烁的问题。但是在吸顶库中又引入了新的问题,即快速向下滑动的过程中,吸顶后面的视图会不合时宜的出现在视觉中,造成另外一种情况的闪烁

3.1 使用post方式+OnPreDrawListener解决

使用post+alpha在快速滑动时会出现,吸顶短暂消失,漏出吸顶背后的View,这种闪烁的效果如果交互给用户,肯定会被喷的。于是又陷入了苦苦思索的状态,然后从View的绘制流程的各个节点尝试了一遍,了无收获,直到有一天尝试了下ViewTreeObserver.addOnPreDrawListener方法,意外的发现可以解决以上的问题,开心~ 解决方案如下
post+OnPreDrawListener方式解决

3.2 效果

完美解决了以上的所有问题

推荐阅读


1. 事件分发四部曲

1.1. 事件分发四部曲之一深度遍历讲解事件分发

1.2. 事件分发四部曲之二详细讲解Android嵌套滑动机制

1.3. 事件分发四部曲之三详细讲解CoordinatorLayout事件分发机制

1.4. 事件分发四部曲之四详细讲解BottomSheetBehavior事件分发机制

2. RecyclerView相关

2.1. 当RecyclerView滚动时它干了什么

2.2. 记录瀑布流布局遇到的一个坑

2.3. 详细讲解RecyclerView动画实现原理之一

2.4. 详细讲解RecyclerView动画实现原理之二

2.5. 聊聊RecyclerView缓存机制

3. Material Design相关

3.1. 使用AppBarLayout实现京东分类页面二次吸顶功能

3.2. 了解AppBarLayout应该从这几个方面入手

3.3. 一文搞懂BottomSheetBehavior

4. 开源库相关

4.1. 我开源了一个RecyclerView吸顶库

欢迎关注我的公众号:字节小站

这是一个分享Android技术干货的公众号,如果你觉得我的文章能够让你学习到东西,希望你可以帮我分享其他更多的人。如果你有好的文章,欢迎投稿,让我们一起来分享。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值