Android NestedScroll嵌套滑动机制解析

Android NestedScroll嵌套滑动机制解析

目录

Android提供了一个官方的嵌套滑动机制,让子View实现NestedScrollingChild或者NestedScrollingChild2接口,父布局实现NestedScrollingParentNestedScrollingParent2接口,Android官方还提供了NestedScrollingChildHelperNestedScrollingChildHelper两个帮助类,让开发者更容易实现嵌套滑动的逻辑.

最初的接口和接口2的区别

子View的接口有NestedScrollingChildNestedScrollingChild2,NestedScrollingChild2继承于NestedScrollingChild,然后以多态的形式给大部分的方法都加了一个int类型的NestedScrollType,这个int值是用来区分是用户触摸滑动还是其他滑动的,其共有两个类型

    /**
     * Indicates that the input type for the gesture is from a user touching the screen.
     */
    public static final int TYPE_TOUCH = 0;

    /**
     * Indicates that the input type for the gesture is caused by something which is not a user
     * touching a screen. This is usually from a fling which is settling.
     */
    public static final int TYPE_NON_TOUCH = 1;

根据英文释义,TYPE_TOUCH为用户触摸操作的类型,TYPE_NON_TOUCH为非用户触摸操作类型,而且主要用于代码中的惯性操作,比如View滑动时的惯性滑动.

原始接口NestedScrollingChild默认类型为TYPE_TOUCH,如果需要实现子View和父View的惯性嵌套滑动则需要实现NestedScrollingChild2接口

父View接口NestedScrollingParentNestedScrollingParent2和子View一样在大部分方法中添加了NestedScrollType,在此不做赘述.

接口方法介绍

在此只介绍原始接口的方法,对于扩展的第二接口由于只在原基础上加了一个类型,不多做介绍

NestedScrollingChild

public interface NestedScrollingChild {
   
    /**
     * 启用或者禁止嵌套滑动
     */
    void setNestedScrollingEnabled(boolean enabled);

    /**
     * 用于判断嵌套滑动是否被启用
     */
    boolean isNestedScrollingEnabled();

    /**
     * 开始嵌套滑动,参数为滑动方向,参数有如下几个
     * 
     * 没有滑动方向
     * public static final int SCROLL_AXIS_NONE = 0;
     * 
     * 横向滑动
     * public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0;
     * 
     * 纵向滑动
     * public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
     * 
     * 其返回值代表父View是否接受嵌套滑动,如果不接受返回false,后续的嵌套滑动都将失效
     */
    boolean startNestedScroll(@ScrollAxis int axes);

    /**
     * 是否有实现了NestedScrollingParent的父View
     * 如果父View没有实现接口,此方法返回false,且所有嵌套滑动无效
     */
    boolean hasNestedScrollingParent();

    /**
     * 分发嵌套滑动事件,在子View滑动处理完之后调用
     */
    boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow);

    /**
     * 分发预嵌套滑动事件,在子View滑动处理之前调用
     */
    boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
            @Nullable int[] offsetInWindow);

    /**
     * 分发嵌套滑动的惯性滑动处理,返回值表示是否处理
     */
    boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);

    /**
     * 分发嵌套滑动的惯性滑动预处理,返回值表示是否处理,在子View处理之前调用
     */
    boolean dispatchNestedPreFling(float velocityX, float velocityY);
}

NestedScrollingParent

此接口都是NestedScrollingChild的接口回调,在子View接口方法被调用时便会调用父View的NestedScrollingParent的方法,它们有着一一对应的关系,具体如下

NestedScrollingChild NestedScrollingParent 备注
startNestedScroll onStartNestedScroll 前者的调用会触发后者的调用,然后后者的返回值将决定后续的嵌套滑动事件是否能传递给父View,如果返回false,父View将不处理嵌套滑动事件,一般前者的返回值即后者的返回值
onNestedScrollAccepted 如果onStartNestedScroll返回true,则回调此方法
stopNestedScroll onStopNestedScroll
dispatchNestedScroll onNestedScroll
dispatchNestedPreScroll onNestedPreScroll
dispatchNestedFling onNestedFling
dispatchNestedPreFling onNestedPreFling
getNestedScrollAxes 获得滑动方向,没有回调,为主动调用的方法

使用方法

子View接口的使用

子View接口常用实现

子View的接口通常都是借助NestedScrollingChildHelper通过委派模式实现的,没有直接写在某个嵌套滑动子View里,提升了代码复用性,还是很高明的做法.

具体如下

在类中声明NestedScrollingChildHelper对象

private final NestedScrollingChildHelper mChildHelper;

然后在子View构造函数中实例化

mChildHelper = new NestedScrollingChildHelper(this);

接下来实现NestedScrollingChild接口

  @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        mChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return mChildHelper.startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll() {
        mChildHelper.stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        return mChildHelper.hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
            int dyUnconsumed, int[] offsetInWindow) {
        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
                offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, 
  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值