问题
问题现象: CoordinatorLayout嵌套 上半部分AppBarLayout+下半部分RecyclerView, 对下半部分RecyclerView的显示隐藏做操作(如吟唱recyclerView展示一个ErrorLayout or EmptyLayout, 会导致AppBarLayout区域不再响应滑动, 这个bug较容易忽略, 因为滑动界面上的下半部分立即可以恢复滑动使现象消失.
这个问题是由系统源码导致, 里记录一下原因分析:
从CoordinatorLayout看起:
HeaderBehavior:
AppBarlayout:
lastNestedScrollingChildRef的赋值只有两处,
@Override
public boolean onStartNestedScroll(
@NonNull CoordinatorLayout parent,
@NonNull T child,
@NonNull View directTargetChild,
View target,
int nestedScrollAxes,
int type) {
//省略...
// A new nested scroll has started so clear out the previous ref
lastNestedScrollingChildRef = null;
//省略...
return started;
}
@Override
public void onStopNestedScroll(
CoordinatorLayout coordinatorLayout, @NonNull T abl, View target, int type) {
//省略...
// Keep a reference to the previous nested scrolling child
lastNestedScrollingChildRef = new WeakReference<>(target);
}
所以lastNestedScrollingChildRef得含义和名字一样, 是上一次的嵌套滚动view, 如果我们滑动了RecyclerView, 那么这个值就是RecyclerView, 如果此时把RecyclerView隐藏, 再滑动AppBarLayout区域, 就会滑不动了, 因为AppBarLayout中CanDragView中判断RecyclerView isShown()
为false.
为什么滑动一下AppBarLayout下面的错误界面或空界面区域就会恢复呢? 因为在View中有如下一段代码:
public boolean dispatchTouchEvent(MotionEvent event) {
//...
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
//...
由前面源码得知, stopNestedScroll();
中会对lastNestedScrollingChildRef重新赋值. 这也是为什么是在 lastNestedScrollingChildRef是在stopNestedScroll();
中赋值, 而每次开始滑动是lastNestedScrollingChildRef总是不为空.
至此, AppBarLayout偶现滑不动的原因就清楚了.
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题