您现在的位置是:主页 > news > 自己做黑彩网站/搜索引擎app

自己做黑彩网站/搜索引擎app

admin2025/4/27 19:42:52news

简介自己做黑彩网站,搜索引擎app,哈尔滨疫情最新静默消息,线上课程制作NestedScrollingParent:以下简称“NSP”,NestedScrollingChild:以下简称“NSC”,这两个接口是嵌套滑动的精髓,是我们实现嵌套滑动遵守的“规则”。 NOTE:本博文非详细原理篇,原理分析网上资料很…

自己做黑彩网站,搜索引擎app,哈尔滨疫情最新静默消息,线上课程制作NestedScrollingParent:以下简称“NSP”,NestedScrollingChild:以下简称“NSC”,这两个接口是嵌套滑动的精髓,是我们实现嵌套滑动遵守的“规则”。 NOTE:本博文非详细原理篇,原理分析网上资料很…

NestedScrollingParent:以下简称“NSP”,NestedScrollingChild:以下简称“NSC”,这两个接口是嵌套滑动的精髓,是我们实现嵌套滑动遵守的“规则”。

NOTE:本博文非详细原理篇,原理分析网上资料很多!!

与传统事件分发相比,好在哪?

  • 方向维度

    -  传统事件分发机制

      方向:父控件 -> 子控件,且是一锤子买卖,即事件总是先传递给父控件,父控件不拦截该事件,则该事件才会传递给子控件,一旦父控件拦截了该事件,则子View就没有机会处理该事件了,同一事件序列的事件均由父控件处理。

同一事件序列:从手指按下屏幕的那刻起,到抬起手指,这中间产生的一系列事件:一个ACTION_DOWN、N个ACTION_MOVE、一个ACTION_UP等。

    -  嵌套滑动机制

      方向:子控件 -> 父控件,且不是一锤子买卖,且嵌套滑动由子控件来触发,且在同一事件序列中,父控件和子控件都有机会处理该事件。

  • 体验维度

   注意:传统的事件分发机制一样可以实现嵌套滑动。

    -  传统事件分发机制

       体验相对较差,基于传统事件分发与拦截的特点,实现的嵌套滑动不连贯,比如向上滑动到一定位置之后,如吸顶的位置,如果用户不抬起手指,则页面就不会继续向上滑动了。为啥?因为不抬起手指,产生的事件还是同一事件序列,还是由父View消耗,子View没机会消耗。

    -  嵌套滑动机制

        由于同一事件序列,父子View都有机会参与处理,因此体验较好。至于怎么做到[同一事件序列,父子View都有机会参与]的,本文后面会讲。

  • 复杂维度

       嵌套滑动机制实现嵌套滑动更容易一些,为啥?

       传统事件分发机制需要父控件首先拦截处理滑动事件,当到达比如吸顶位置了,此时滑动事件不再满足父控件的处理要求了,此时子View才有机会处理后面的滑动(此处用户应该抬一把手指,o(∩_∩)o )。

        而嵌套滑动机制则不需要,因为官方(>=5.0)SDK中的View和ViewGroup已经以普通方法的方式实现了NSC和NSP中的所有方法了。那是不是意味着不需要我们开发者参与,View和ViewGroup就智能的展示出嵌套滑动的效果了?

        非也。上面说了,View和ViewGroup是以普通方法的方式实现了NSC和NSP中的方法的,而不是回调方法,所以是否开启嵌套滑动,以及如何去使用这些已经实现的方法去使用嵌套滑动,那是开发者自己的事情。

  • 相同点

为了实现连贯的嵌套滑动,谷歌在Lollipop(Android 5.0)时,推出了NestedScrolling机制。该机制并没有脱离传统的事件分发机制,而是在原有的事件分发机制之上,为系统的自带的ViewGroup和View都增加了手势滑动与处理fling的方法。(版本兼容问题,后面说)

如何开启嵌套滑动?

是否开启嵌套滑动是View自己的事情,触发嵌套滑动的节点是子View的ACTION_DOWN事件处理 - 事件拦截和事件处理回调中对此事件的处理,当然也要求它有一个支持嵌套滑动的父View,不然还玩个毛线。

嵌套滑动必须用协调布局和Behavior吗?

非必须,自定义View实现NSP或者NSC即可实现嵌套滑动。协调布局也是一个实现了NSP的View,Behavior只是协调布局特有的用于实现子View联动的手段。通过协调布局和Behavior只是实现嵌套滑动的一种便捷方式。

实现NSC的子View是否必须是支持嵌套滑动的父View的直接子View呢?

非必须,协调布局对Behavior有这个要求,即直接子View设置Behavior才有效,否则,无效。

版本兼容问题

上面说了,嵌套滑动是5.0出现的,那么5.0之前呢?

  • 5.0之前,提供了NSP和NSC接口,以及对应的帮助类!!!开发者实现NSP和NSC即可!!
  • 5.0之后,View或者ViewGroup中已经以普通方法的形式实现了NSC和NSP中的所有方法!!

流程 - 详析

注意:实现嵌套滑动,关键点:

  • 子View:主要的工作是调用时机,及调用完成后,对剩余距离的滑动处理。

        -  5.0 之前,子View实现NSC,并在对应NSC的实现方法中直接调用对应的NSCHelper里面的方法就可以了。然后就是关注调用时机,及调用完成后对剩余距离的处理,比如滑动等。

public class NestedScrollingChildView extends View implements NestedScrollingChild {private NestedScrollingChildHelper nestedScrollingChildHelper = new NestedScrollingChildHelper(this);public NestedScrollingChildView(Context context) {super(context);}public NestedScrollingChildView(Context context, AttributeSet attrs) {super(context, attrs);}// 以下是实现NSC所需要的所有方法@Overridepublic void setNestedScrollingEnabled(boolean enabled) {nestedScrollingChildHelper.setNestedScrollingEnabled(enabled);}@Overridepublic boolean isNestedScrollingEnabled() {return nestedScrollingChildHelper.isNestedScrollingEnabled();}@Overridepublic boolean startNestedScroll(int axes) {return nestedScrollingChildHelper.startNestedScroll(axes);}@Overridepublic boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {return nestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);}@Overridepublic boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {return nestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);}@Overridepublic boolean hasNestedScrollingParent() {return nestedScrollingChildHelper.hasNestedScrollingParent();}@Overridepublic boolean dispatchNestedPreFling(float velocityX, float velocityY) {return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);}@Overridepublic boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);}@Overridepublic void stopNestedScroll() {nestedScrollingChildHelper.stopNestedScroll();}
}

        -  5.0 之后,只需关注调用时机,及调用完成后对剩余距离的处理,比如滑动等。

  • 父View:

       在对应的NSP方法中实现距离处理逻辑即可。(不借助NSPHelper也没啥问题,NSPHelper中的逻辑很少)

分析主要从子View着手,因为父View的方法都是子View主动调用的

分析NestedScrollingChildHelper的源码,因为NSCHelper中方法对应方法的逻辑就是嵌套滑动的对子View的规则实现

-      开始 -  startNestedScroll - 调用时机:ACTION_DOWN事件

    public boolean startNestedScroll(@ScrollAxis int axes, @NestedScrollType int type) {if (hasNestedScrollingParent(type)) {// Already in progressreturn true;}// 子View要支持嵌套滑动,需要调用setNestedScrollingEnabled设置为trueif (isNestedScrollingEnabled()) {ViewParent p = mView.getParent();View child = mView;while (p != null) {// 如果父View接收嵌套滑动// 子View会调用父View的onStartNestedScroll和onNestedScrollAccepted方法if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes, type)) {setNestedScrollingParentForType(type, p);ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes, type);return true;}if (p instanceof View) {child = (View) p;}// 找到一个支持嵌套滑动的父Viewp = p.getParent();}}return false;}

-      滑动前,先通知支持嵌套滑动的父View,父View会根据业务选择滑动或者不滑动

        -   dispatchNestedPreScroll  -  调用时机  -  ACTION_MOVE

        -   可以看到 父View的onNestedPreScroll方法被调用,之后子View可以通过consumed数组得到消耗了多少距离

    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,@Nullable int[] offsetInWindow, @NestedScrollType int type) {if (isNestedScrollingEnabled()) {final ViewParent parent = getNestedScrollingParentForType(type);if (parent == null) {return false;}......// 父View的onNestedPreScroll方法ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);......return consumed[0] != 0 || consumed[1] != 0;} else if (offsetInWindow != null) {offsetInWindow[0] = 0;offsetInWindow[1] = 0;}}return false;}

该方法返回true,父View消耗了一段距离,false - 未消耗。

调用完此方法,子View就可以继续完成剩余距离的滑动了。

-  滑动完成,仍然要通知父View

  -  调用dispatchNestedScroll方法,在此方法中,父View的onNestedScroll方法被调用;

其余方法都是类似,略了。一句话,子View行动前,需先通知父View,父View处理完了,子View收拾剩下的。