Behavior与嵌套滚动
Behavior提供了以下相关方法来处理CoordinatorLayout中其他View的嵌套滚动事件。每个方法除了多了参数child(指定该Behavior的View)外,和NestedScrollingParent的方法含义一样。
public static abstract class Behavior<V extends View> {
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
V child, View directTargetChild, View target, int nestedScrollAxes) {
return false;
}
public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child,
View directTargetChild, View target, int nestedScrollAxes) {
}
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
}
public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
}
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dx, int dy, int[] consumed) {
}
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target,
float velocityX, float velocityY, boolean consumed) {
return false;
}
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
float velocityX, float velocityY) {
return false;
}
}
其原理基本是这样的,CoordinatorLayout实现了NestedScrollingParent接口,CoordinatorLayout在每个接口方法中调用Behavior的对应方法。看源码。
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
boolean handled = false;
final int childCount = getChildCount();
// 遍历每个View
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 如果Behavior不为空则调用Behavior的onStartNestedScroll方法。
final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child, target,
nestedScrollAxes);
handled |= accepted; // 返回值handled是每个Behavior的每个处理结果的或值
lp.acceptNestedScroll(accepted);
} else {
//acceptNestedScroll方法是设置mDidAcceptNestedScroll的布尔值,方便后面判断Behavior是否处理嵌套滚动
lp.acceptNestedScroll(false);
}
}
return handled;
}
@Override
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
mNestedScrollingDirectChild = child;
mNestedScrollingTarget = target;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 子View处理嵌套滚动且Behavior不为空,则调用Behavior的onNestedScrollAccepted方法。
viewBehavior.onNestedScrollAccepted(this, view, child, target, nestedScrollAxes);
}
}
}
@Override
public void onStopNestedScroll(View target) {
mNestedScrollingParentHelper.onStopNestedScroll(target);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 子View处理嵌套滚动且Behavior不为空,则调用Behavior的onStopNestedScroll方法。
viewBehavior.onStopNestedScroll(this, view, target);
}
lp.resetNestedScroll(); // 把mDidAcceptNestedScroll设为false。
lp.resetChangedAfterNestedScroll(); // 把mDidChangeAfterNestedScroll设为false。
}
mNestedScrollingDirectChild = null;
mNestedScrollingTarget = null;
}
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
final int childCount = getChildCount();
boolean accepted = false;
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 子View处理嵌套滚动且Behavior不为空,则调用Behavior的onNestedScroll方法。
viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed);
accepted = true;
}
}
if (accepted) {
// 调用onChildViewsChanged方法来调整滚动后View的位置
onChildViewsChanged(EVENT_NESTED_SCROLL);
}
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
int xConsumed = 0;
int yConsumed = 0;
boolean accepted = false;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
mTempIntPair[0] = mTempIntPair[1] = 0;
// 子View处理嵌套滚动且Behavior不为空,则调用Behavior的onNestedPreScroll方法。
viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair);
// 累计被消耗的滚动距离
xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
: Math.min(xConsumed, mTempIntPair[0]);
yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
: Math.min(yConsumed, mTempIntPair[1]);
accepted = true;
}
}
consumed[0] = xConsumed;
consumed[1] = yConsumed;
if (accepted) {
// 调用onChildViewsChanged方法来调整滚动后View的位置
onChildViewsChanged(EVENT_NESTED_SCROLL);
}
}
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
boolean handled = false;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 子View处理嵌套滚动且Behavior不为空,则调用Behavior的onNestedFling方法。
handled |= viewBehavior.onNestedFling(this, view, target, velocityX, velocityY,
consumed);
}
}
if (handled) {
// // 调用onChildViewsChanged方法来调整滚动后View的位置
onChildViewsChanged(EVENT_NESTED_SCROLL);
}
return handled;
}
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
boolean handled = false;
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View view = getChildAt(i);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (!lp.isNestedScrollAccepted()) {
continue;
}
final Behavior viewBehavior = lp.getBehavior();
if (viewBehavior != null) {
// 子View处理嵌套滚动且Behavior不为空,则调用onNestedPreFling方法。
handled |= viewBehavior.onNestedPreFling(this, view, target, velocityX, velocityY);
}
}
// 为啥这里没有调用onChildViewsChanged方法呢???
return handled;
}