最后
文章所有资料全部已经打包整理好,另外小编手头上整理了大量Android架构师全套学习资料,Android核心高级技术PDF文档+全套高级学习资料+视频+2021 BAT 大厂面试真题解析
资料展示:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
private boolean dispatchNestedScrollInternal(int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow,
@NestedScrollType int type, @Nullable int[] consumed) {
if (isNestedScrollingEnabled()) {
final ViewParent parent = getNestedScrollingParentForType(type);
if (parent == null) {
return false;
}
if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
int startX = 0;
int startY = 0;
if (offsetInWindow != null) {
mView.getLocationInWindow(offsetInWindow);
startX = offsetInWindow[0];
startY = offsetInWindow[1];
}
if (consumed == null) {
consumed = getTempNestedScrollConsumed();
consumed[0] = 0;
consumed[1] = 0;
}
ViewParentCompat.onNestedScroll(parent, mView,
dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed);
if (offsetInWindow != null) {
mView.getLocationInWindow(offsetInWindow);
offsetInWindow[0] -= startX;
offsetInWindow[1] -= startY;
}
return true;
} else if (offsetInWindow != null) {
offsetInWindow[0] = 0;
offsetInWindow[1] = 0;
}
}
return false;
}
复制代码
其中两个二维数组作为结果回传;通过父容器的onNestedScroll方法进行处理并把滑动处理详情放入两个二维数组中,常用的详情为消耗长度情况;返回结果表示滑动前是否处理
2.3.5 滑翔通知
滑翔也有两个时机
滑翔前
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
if (isNestedScrollingEnabled()) {
ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
if (parent != null) {
return ViewParentCompat.onNestedPreFling(parent, mView, velocityX,
velocityY);
}
}
return false;
}
复制代码
返回结果表明父容器的是否处理滑翔;父容器是通过onNestedPreFling进行处理
滑翔后
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
if (isNestedScrollingEnabled()) {
ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
if (parent != null) {
return ViewParentCompat.onNestedFling(parent, mView, velocityX,
velocityY, consumed);
}
}
return false;
}
复制代码
返回结果表明父容器的是否处理滑翔;父容器是通过onNestedFling进行处理
滑翔是一个互斥处理的过程,而滑动是一个接力的过程
2.3.6 滑动结束通知
public void stopNestedScroll() {
stopNestedScroll(TYPE_TOUCH);
}
public void stopNestedScroll(@NestedScrollType int type) {
ViewParent parent = getNestedScrollingParentForType(type);
if (parent != null) {
// 通知嵌套父容器,滑动结束
ViewParentCompat.onStopNestedScroll(parent, mView, type);
setNestedScrollingParentForType(type, null); // 清理父容器引用
}
}
复制代码
3、NestedScrollingParentHelper类
作为嵌套滑动的父容器角色,其只有接受通知时处理即可,情况没有子视图角色那么复杂;而辅助类里仅仅是对滑动方向做了声明周期处理;
成员变量
private int mNestedScrollAxesTouch; // Touch事件时,接受处理时,事件的滑动方法
private int mNestedScrollAxesNonTouch; // 非Touch事件时,接受处理时,事件的滑动方法
复制代码
3.1 滑动方向获取
public int getNestedScrollAxes() {
return mNestedScrollAxesTouch | mNestedScrollAxesNonTouch;
}
复制代码
3.2 滑动方向设置
public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
@ScrollAxis int axes) {
onNestedScrollAccepted(child, target, axes, ViewCompat.TYPE_TOUCH);
}
public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
@ScrollAxis int axes, @NestedScrollType int type) {
if (type == ViewCompat.TYPE_NON_TOUCH) {
mNestedScrollAxesNonTouch = axes;
} else {
mNestedScrollAxesTouch = axes;
}
}
复制代码
3.3 滑动方向重置
public void onStopNestedScroll(@NonNull View target) {
onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
}
public void onStopNestedScroll(@NonNull View target, @NestedScrollType int type) {
if (type == ViewCompat.TYPE_NON_TOUCH) {
mNestedScrollAxesNonTouch = ViewGroup.SCROLL_AXIS_NONE;
} else {
mNestedScrollAxesTouch = ViewGroup.SCROLL_AXIS_NONE;
}
}
复制代码
作为一是具有兼容性实现的嵌套滑动容器,它必须实现下面接口
-
滑动容器接口ScrollingView
-
嵌套滑动父容器接口NestedScrollingParent3
-
嵌套滑动子视图接口NestedScrollingChild3
嵌套接口,可以根据容器角色选择实现;方法实现需要利用辅助类
从上面对两个辅助类解读;对他们已经实现的功能做了归纳
-
嵌套是否支持
-
嵌套通知
-
嵌套滑动方向
也就是作为子视图角色的实现方法基本使用辅助类即可,而嵌套父容器角色需要我们增加实现逻辑;需要实现从功能上划分:
-
作为嵌套子视图设置,
-
作为嵌套父容器的实现
-
滑动接力处理,以及滑翔处理
4.1 嵌套子视图支持
构造器中进行setNestedScrollingEnabled(true)方法进行设置
setNestedScrollingEnabled方法
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
复制代码
4.2 嵌套父容器的支持
public boolean onStartNestedScroll(
@NonNull View child, @NonNull View target, int nestedScrollAxes) {
return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
}
public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes,
int type) {
return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
复制代码
可滑动方向判断进而决定是否支持的;支持时的处理如下
public void onNestedScrollAccepted(
@NonNull View child, @NonNull View target, int nestedScrollAxes) {
onNestedScrollAccepted(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
}
public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes,
int type) {
mParentHelper.onNestedScrollAccepted(child, target, axes, type);
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, type);
}
复制代码
其还是一个子视图角色,所以,其需要继续传递这个滑动开始的信号;可见嵌套默认处理中:其实是一个嵌套滑动容器链表,中间也可能存在滑动容器(不支持嵌套),链表组后一个容器的‘父’容器也还可能是嵌套滑动;这些情况造成的一个原因是同时是父容器还是子视图才会继续分发;这个链头容器必定是个嵌套子视图角色,中间即是子视图角色也是父容器角色,链尾容器必定是个嵌套父容器角色
时机
在down事件中,调用startNestedScroll方法
4.3 利用辅助类重写
下面方法利用了辅助类直接重写
-
嵌套父容器存在判断:hasNestedScrollingParent
-
子视图是否支持嵌套滑动:setNestedScrollingEnabled、isNestedScrollingEnabled
-
开始通知:startNestedScroll
-
滑动分发:dispatchNestedPreScroll、dispatchNestedScroll
-
滑翔分发:dispatchNestedPreFling、dispatchNestedFling
-
结束通知:stopNestedScroll
参数中涉及到滑动类型时,均采用ViewCompat.TYPE_TOUCH作为默认类型
4.4 滑动接力处理
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
}
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
int type) {
dispatchNestedPreScroll(dx, dy, consumed, null, type);
}
复制代码
其作为父容器,本身对事件并没有处理,而是作为子视图继续分发下去;时机move事件中嵌套子视图处理滑动之前
public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
onNestedScrollInternal(dyUnconsumed, ViewCompat.TYPE_TOUCH, null);
}
private void onNestedScrollInternal(int dyUnconsumed, int type, @Nullable int[] consumed) {
final int oldScrollY = getScrollY();
scrollBy(0, dyUnconsumed);
final int myConsumed = getScrollY() - oldScrollY;
if (consumed != null) {
consumed[1] += myConsumed;
}
final int myUnconsumed = dyUnconsumed - myConsumed;
mChildHelper.dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null, type, consumed);
}
复制代码
父容器首先处理了滑动,然后把处理后的情况继续传递;时机move事件,嵌套子视图处理之后
4.5 滑翔互斥处理
public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
return dispatchNestedPreFling(velocityX, velocityY);
}
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
复制代码
不进行处理,而是做为嵌套子视图继续分发;时机up事件,拦截时,嵌套子视图处理之前
public boolean onNestedFling(
@NonNull View target, float velocityX, float velocityY, boolean consumed) {
if (!consumed) {
dispatchNestedFling(0, velocityY, true);
fling((int) velocityY);
return true;
}
return false;
}
复制代码
如果接受到通知时,未处理,则进行处理;并做为嵌套子view继续通知处理;时机up事件,拦截时,嵌套子视图处理之后
4.6 滑动结束
public void onStopNestedScroll(@NonNull View target) {
onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
}
public void onStopNestedScroll(@NonNull View target, int type) {
mParentHelper.onStopNestedScroll(target, type);
stopNestedScroll(type);
}
public void stopNestedScroll(int type) {
mChildHelper.stopNestedScroll(type);
}
复制代码
由于还是嵌套子视图角色,还需要通知其处理的嵌套父容器结束;时机up、cancel事件时
4.7 嵌套子视图优先处理
android中,从容器的默认拦截机制来看,父容器优先拦截;但是嵌套时做了额外判断,
滑动事件拦截中是这样判断的
yDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0)
复制代码
滑动的坐标轴为0,也就是既不是x轴、也不是y轴;这说明,它作为嵌套父容器时,没有嵌套子容器传递给它;
另外如果滑动已经被拦截处理,则不希望其它进行再次拦截;这时由于嵌套拦截体系已经提供了交互的方法,如果不这样处理,就会导致和默认的事件机制冲突;因此,如果有这种情况,那就把重写父容器,让其支持嵌套滑动吧
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
交互的方法,如果不这样处理,就会导致和默认的事件机制冲突;因此,如果有这种情况,那就把重写父容器,让其支持嵌套滑动吧
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!