返回介绍

NestedScrolling 事件处理

发布于 2024-12-23 21:14:47 字数 4196 浏览 0 评论 0 收藏 0

当 CoordinatorLayout 的子控件有 NestedScrollingChild 产生 Nested 事件的时候.会调用 onStartNestedScroll 这个方法

  @Override
  public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
      View directTargetChild, View target, int nestedScrollAxes) {
      return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//滑动 Y 轴方向的判断
  }

返回值 true :表示 BehaviorView 要和 NestedScrollingChild 配合消耗这个 NestedScrolling 事件,这里可以看出只要是纵向的滑动都会返回 true.

onNestedPreScroll

NestedScrollingChild 的在滑动的时候会触发 onNestedPreScroll 方法,询问 BehaviorView 消耗多少 Y 轴上面的滑动。

  @Override
  public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
      int dy, int[] consumed) {
    View scrollingChild = mNestedScrollingChildRef.get();
    if (target != scrollingChild) {
      return;
    }
    int currentTop = child.getTop();
    int newTop = currentTop - dy;
    if (dy > 0) { // Upward
      if (newTop < mMinOffset) {
        consumed[1] = currentTop - mMinOffset;
        ViewCompat.offsetTopAndBottom(child, -consumed[1]);
        setStateInternal(STATE_EXPANDED);
      } else {
        consumed[1] = dy;
        ViewCompat.offsetTopAndBottom(child, -dy);
        setStateInternal(STATE_DRAGGING);
      }
    } else if (dy < 0) { // Downward
      if (!ViewCompat.canScrollVertically(target, -1)) {
        if (newTop <= mMaxOffset || mHideable) {
          consumed[1] = dy;
          ViewCompat.offsetTopAndBottom(child, -dy);
          setStateInternal(STATE_DRAGGING);
        } else {
          consumed[1] = currentTop - mMaxOffset;
          ViewCompat.offsetTopAndBottom(child, -consumed[1]);
          setStateInternal(STATE_COLLAPSED);
        }
      }
    }
    dispatchOnSlide(child.getTop());
    mLastNestedScrollDy = dy;
    mNestedScrolled = true;
  }

onNestedPreScroll 方法主要做几件事情:

  1. 判断发起 NestedScrolling 的 View 是否是我们在 onLayoutChild 找到的那个控件.不是的话,不做处理.不处理就是不消耗 y 轴,把所有的 Scroll 交给发起的 View 自己消耗。
  2. 根据 dy 判断方向,根据之前的偏移范围算出偏移量.使用 ViewCompat.offsetTopAndBottom 对 BehaviorView 进行偏移操作。
  3. 消耗 Y 轴的偏移量.发起 NestedScrollingChild 会自动响应剩下的部分

其中 comsume[]是个数组,consumed[1]表示 Parent 在 Y 轴消耗的值, NestedScrollingChild 会消耗除 BehaviorView 消耗剩下的那部分( 比如: NestedScrollingChild 要滑动 20 像素,因为 BehaviorView 消耗了 10 像素,最后 NestedScrollingChild 只滑动了 10 像素);

onStopNestedScroll 在 Nestd 事件结束触发. 主要做的事情: 根据 BehaviorView 当前的状态对它的最终位置的确定,有必要的话调用 ViewDragHelper.smoothSlideViewTo 进行滑动. ####注意 当你是往下滑动且 Hideable 为 true ,他会 使用上面计算的 Y 轴的速率的判断.是否应该切换到 Hideable 的状态。

onNestedPreFling

这个是 NestedScrollingChild 要滑行时候触发的,询问 BehaviorView 是否消耗这个滑行。


@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
                                float velocityX, float velocityY) {
    return target == mNestedScrollingChildRef.get() &&
            (mState != STATE_EXPANDED ||
                    super.onNestedPreFling(coordinatorLayout, child, target,
                            velocityX, velocityY));
}

处理逻辑是:发起 Nested 事件要与 onLayoutChild 找到的那个控件一致且当前状态是一个 STATE_EXPANDED 状态。

返回值: true 表示 BehaviorView 消耗滑行事件,那么 NestedScrollingChild 就不会有滑行了

ViewDragHelper.Callback

ViewDragHelper 网上教程挺多的,就不多讲了,他主要是处理滑动拖拽的。

小技巧:在说说一个小技巧,Android 官网中有这样一句话: Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android ,就是说枚举比静态常量更加耗费内存,我们应该避免使用,然后我看 BottomSheetBehavior 源码中 mState 是这样定义的:

  public static final int STATE_DRAGGING = 1;
  public static final int STATE_SETTLING = 2;
  public static final int STATE_EXPANDED = 3;
  public static final int STATE_COLLAPSED = 4;
  public static final int STATE_HIDDEN = 5;

  @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
  @Retention(RetentionPolicy.SOURCE)
  public @interface State {}

  @State
  private int mState = STATE_COLLAPSED;

弥补了 Android 不建议使用枚举的缺陷。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文