CoordinatorLayout和Behavior(二)

529 阅读3分钟
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;
}