NestedScrolling(嵌套滚动)

2023-12-24 20:58

本文主要是介绍NestedScrolling(嵌套滚动),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于自定义Behavior,其中还有一种是实现NestedScrolling效果的,这种效果很常见,比如像支付宝的首页,有道词典的首页等,有了这种嵌套滚动的机制可以实现很多复杂的界面效果。CoordinatorLayout就使用了这套机制,一般我们使用它直接做父View,因为它实现了NestedScrollingParent接口,那么下面我们说一说NestedScrolling。

要想了解NestedScrolling我们就得说一说NestedScrollingParentNestedScrollingChild

NestedScrollingParent
public interface NestedScrollingParent {/***响应一个子View视图,是否执行可嵌套的滚动操作。*当子View视图调用了startNestedScroll(),Parent会收到onStartNestedScroll()回调,*决定是否需要配合Child来一起进行处理滑动,如果需要配合,还会回调onNestedScrollAccepted()。*当嵌套的滚动完成后,这个ViewParent将会回调onStopNestedScroll(View)。* @param 这个ViewParent所包含的直接子对象* @param 嵌套滚动的View* @param 嵌套滚动的方向SCROLL_AXIS_HORIZONTAL,SCROLL_AXIS_VERTICAL或者两者                         * @return 如果此ViewParent接受嵌套滚动操作,则返回true*/public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);/***此方法将在onStartNestedScroll返回true之后调用*这个方法中可以通知需要嵌套滚动的子View* @param 这个ViewParent包含的直接子对象* @param 嵌套滚动的View* @param 嵌套滚动的方向SCROLL_AXIS_HORIZONTAL,SCROLL_AXIS_VERTICAL或者两者 *                         */public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);/*** *在嵌套滚动操作后执行资源回收等操作*当一个嵌套的滚动停止时,这个方法将被调用* @param  嵌套滚动的View*/public void onStopNestedScroll(View target);/*** 当ViewParent正在进行嵌套滚动的时候,调用此方法* 滑动的距离消耗部分和未消耗部分都会通知给ViewParent* @param target 嵌套滚动的子View* @param dxConsumed 表示target已经消费的x方向的距离* @param dyConsumed 表示target已经消费的x方向的距离* @param dxUnconsumed 表示x方向剩下的滑动距离* @param dyUnconsumed 表示y方向剩下的滑动距离*/public void onNestedScroll(View target, int dxConsumed, int dyConsumed,int dxUnconsumed, int dyUnconsumed);/*** 如果父视图会在嵌套滚动子View之前先滚动一段距离,那就用这个方法,也* 就是发生嵌套滚动之前回调* @param 初始化嵌套滚动的目标视图* @param 本次滚动产生的x方向的滚动总距离* @param dy 本次滚动产生的y方向的滚动总距离* @param 表示viewParent要消费的滚动距离,consumed[0]和consumed[1]分别表示viewParent在x和y方向上消费的距离.*/public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);/***如果一个嵌套滚动子视图fling,但这是它位于它自己的内容的边缘,*那么它就可以使用这个方法将它委托给它嵌套的滚动的ViewParent。* ViewParent可以消费或者观察子View的fling动作* @param target View that initiated the nested scroll* @param 水平方向的速度* @param 垂直方向速度* @param 如果子View消费了fling操作,返回true,反之亦然* @return 如果ViewParent消费了fling或者以其他方式响应fling都返回true*/public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);/*** * 嵌套滚动之前,响应fling* @param target View that initiated the nested scroll* @param 水平方向的速度* @param 垂直方向速度* @return 如果viewParent在target之前消费了fling返回true*/public boolean onNestedPreFling(View target, float velocityX, float velocityY);/*** ** @return 返回嵌套滚动的方向(标识)* @see ViewCompat#SCROLL_AXIS_HORIZONTAL* @see ViewCompat#SCROLL_AXIS_VERTICAL* @see ViewCompat#SCROLL_AXIS_NONE*/public int getNestedScrollAxes();
}


NestedScrollingChild
public interface NestedScrollingChild {  /** * 启用或禁用此视图的嵌套滚动* 如果此属性设置为true,则视图将会启动兼容ViewParent嵌套滚动的操作 * *  @param true为启用嵌套滚动,false为禁用*/  public void setNestedScrollingEnabled(boolean enabled);  /** * 判断嵌套滑动是否可用 * * @return 如果该视图启用嵌套滚动,则为true*/  public boolean isNestedScrollingEnabled();  /** * 沿着设定好的坐标轴方向开始嵌套滚动    * 该视图将在启动滚动操作时调用startNestedScroll,* 如果startNestedScroll返回true,那么就会寻找ViewParent* @param axes 表示方向轴,有横向和竖向*/  public boolean startNestedScroll(int axes);  /** * 停止正在进行的嵌套滚动* 当嵌套滚动不在进行中时调用此方法是没有什么卵用的。*/  public void stopNestedScroll();  /** * 如果此视图具有嵌套的滚动的ViewParent,则返回true。* @return whether this view has a nested scrolling parent*/  public boolean hasNestedScrollingParent();  /** * 在子View的onInterceptTouchEvent或者onTouch中,调用该方法通知父View滑动的距离* dispatchNestedPreScroll可以为,想在嵌套滚动中的父视图,提供了消耗部分或全部滚动操作机会。*(在子视图嵌套滚动消耗距离之前)* @param dx  x轴上滑动的距离* @param dy  y轴上滑动的距离* @param consumed 父view消费掉的scroll长度* @param offsetInWindow   子View的窗体偏移量* @return 支持的嵌套的父View 是否处理了 滑动事件 */  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);  /** * 支持嵌套滚动的视图的应该调用这个方法来报告当前滚动的信息到当前嵌套的滚动父对象** @param dxConsumed x轴上被消费的距离(横向)* @param dyConsumed y轴上被消费的距离(竖向)* @param dxUnconsumed x轴上未被消费的距离 * @param dyUnconsumed y轴上未被消费的距离 * @param offsetInWindow 子View的窗体偏移量* @return  如果事件被发送,则为true,如果没能发送,则为false。*/  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,  int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);  /** * 滑行时调用 ** @param velocityX x 轴上的滑动速率* @param velocityY y 轴上的滑动速率* @param consumed 如果孩子消费了这个Fling,则为true,否则为false* @return  如果嵌套的滚动父级消耗或以以其他方式对Fling做出反应,则返回true*/  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);  /** * 在这个视图处理之前,将一个fling分发给一个嵌套滚动的父级。** @param velocityX x 轴上的滑动速率* @param velocityY y 轴上的滑动速率 * @return 如果嵌套的滚动父级消费了该Fling,则为true*/  public boolean dispatchNestedPreFling(float velocityX, float velocityY);  
}


这么多的方法和参数,看这真是晕~但实际上,我们不会直接使用这两个接口的。而是使用 NestedScrollingChildHelper或NestedScrollingParentHelper这个辅助类,Android已经实现好了 Child 和 Parent 交互的逻辑。

实现 NestedScrollingChild

如果你有一个滑动的View(自定义或原生控件)需要被用来作为嵌入滑动的子 View,就必须实现本接口。例如:ListView

大体的流程如下:

1.子View需要调用setNestedScrollingEnabled启动嵌套滑动,然后调用startNestedScroll方法,让他去寻找viewParent,
通知ViewParent.

2.然后在子ViewonInterceptTouchEvent或者onTouch中,调用dispatchNestedPreScroll来通知ViewParent需不需要滑动,如果ViewParent要滑动,那么根据方法的3,4参数,返回父view消费掉的scroll长度和子View的窗体偏移量,如果ViewParent没有把所有的距离消耗完,那么子View就可以处理 剩下的距离了。

3.子View调用dispatchNestedScroll方法向ViewParent通知滚动情况,包括子view消费的部分和子view没有消费的部分。
如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。

4.调用stopNestedScroll

CoordinatorLayout就实现了NestedScrollingParent

那么说到嵌套滚动,Behavior在这里面是干啥的呢?下面看看在源码里面做了什么

//滑动开始的调用startNestedScroll(),ViewParent收到onStartNestedScroll() 回调, 
@Overridepublic boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {boolean handled = false;final int childCount = getChildCount();for (int i = 0; i < childCount; i++) {final View view = getChildAt(i);if (view.getVisibility() == View.GONE) {// If it's GONE, don't dispatchcontinue;//决定是否需要配合 Child 一起进行处理滑动,如果需要配合,还会回调 onNestedScrollAccepted()。final LayoutParams lp = (LayoutParams) view.getLayoutParams();final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child, target,nestedScrollAxes);handled |= accepted;lp.acceptNestedScroll(accepted);} else {lp.acceptNestedScroll(false);}}return handled;}@Overridepublic 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) {viewBehavior.onNestedScrollAccepted(this, view, child, target, nestedScrollAxes);}}}@Overridepublic 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) {viewBehavior.onStopNestedScroll(this, view, target);}lp.resetNestedScroll();lp.resetChangedAfterNestedScroll();}mNestedScrollingDirectChild = null;mNestedScrollingTarget = null;}//Child 滑动以后,会调用 onNestedScroll(),回调到 ViewParent 的 onNestedScroll(),//这里就是 Child 滑动后,剩下的给 ViewParent 处理,也就是后于 Child 滑动。@Overridepublic 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);if (view.getVisibility() == GONE) {// If the child is GONE, skip...continue;}final LayoutParams lp = (LayoutParams) view.getLayoutParams();if (!lp.isNestedScrollAccepted()) {continue;}final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,dxUnconsumed, dyUnconsumed);accepted = true;}}if (accepted) {onChildViewsChanged(EVENT_NESTED_SCROLL);}}//ViewParent 可以在这个回调中消费滚动的距离@Overridepublic 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);if (view.getVisibility() == GONE) {// If the child is GONE, skip...continue;}final LayoutParams lp = (LayoutParams) view.getLayoutParams();if (!lp.isNestedScrollAccepted()) {continue;}final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {mTempIntPair[0] = mTempIntPair[1] = 0;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(EVENT_NESTED_SCROLL);}}@Overridepublic 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);if (view.getVisibility() == GONE) {// If the child is GONE, skip...continue;}final LayoutParams lp = (LayoutParams) view.getLayoutParams();if (!lp.isNestedScrollAccepted()) {continue;}final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {handled |= viewBehavior.onNestedFling(this, view, target, velocityX, velocityY,consumed);}}if (handled) {onChildViewsChanged(EVENT_NESTED_SCROLL);}return handled;}@Overridepublic 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);if (view.getVisibility() == GONE) {// If the child is GONE, skip...continue;}final LayoutParams lp = (LayoutParams) view.getLayoutParams();if (!lp.isNestedScrollAccepted()) {continue;}final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {handled |= viewBehavior.onNestedPreFling(this, view, target, velocityX, velocityY);}}return handled;}@Overridepublic int getNestedScrollAxes() {return mNestedScrollingParentHelper.getNestedScrollAxes();}


当CoordiantorLayout接收到了NestedScrollingChild的回调后,把事件交给了Behavior来处理的,
用户来继承CoordiantorLayout.Behavior的时候,这个Behavior其实是个NestedScrollingParent ,
而且还是个加强版的。


以前练习的demo找不到了,等下次重新写一个吧。
隔壁HMI的人,天天在吵吵,头痛( ⊙ o ⊙ )啊!如果这些HMI团队的人是那种妹子团的,我也就忍了。可是这种老男人+大姐的这种团队,就搞的你是真不爽了。

这篇关于NestedScrolling(嵌套滚动)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/533103

相关文章

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

Cortex-A7:ARM官方推荐的嵌套中断实现机制

0 参考资料 ARM Cortex-A(armV7)编程手册V4.0.pdf ARM体系结构与编程第2版 1 前言 Cortex-M系列内核MCU中断硬件原生支持嵌套中断,开发者不需要为了实现嵌套中断而进行额外的工作。但在Cortex-A7中,硬件原生是不支持嵌套中断的,这从Cortex-A7中断向量表中仅为外部中断设置了一个中断向量可以看出。本文介绍ARM官方推荐使用的嵌套中断实现机

UniApp实现漂亮的音乐歌词滚动播放效果

在现代的音乐播放应用中,歌词的展示和滚动播放已经成为了一个非常常见的功能。今天,我们将通过UniApp来实现一个漂亮的歌词滚动播放功能。我们将使用UniApp提供的组件和API来完成这个任务。 页面结构 在页面的模板部分,我们需要创建一个音频播放器和歌词展示区域。使用<scroll-view>组件来实现歌词的滚动效果。 <template><view class="audio-co

多个,多层嵌套module,打aar包

参考https://blog.51cto.com/4259297/1699714 1.在要打包的module中下添加fat-aar.gradle文件。(该文件只能在项目个gradle是2.3.3是才可食用) 2.把项目的gradle修改为2.3.3,但是不打包的gradle依然是以前的。 3.由于打包的的gradle和不打包的是不一样的,所以需要在修改gradle的文件中的添加判断标志

Android studio jar包多层嵌套,Add library '__local_aars__:...@jar' to classpath问题

在添加jar包,早app下的build.gradle中的 implementation files('libs/jar包的名字.jar') 修改为 api files('libs/jar包的名字.jar') implementation 单层引用,只引用当前jar包层, api 多层引用,应用当前jar包层,已经jar包引用的jar包层

vue el-dialog嵌套解决无法点击问题

产生原因: 当你在 el-dialog 上嵌套另一个 el-dialog 窗口时,可能会遇到内部对话框无法点击的问题。这通常是由于嵌套对话框的遮罩层(overlay)或其他样式问题造成的。 解决方案: 如果你的 el-dialog 组件支持 append-to-body 属性,你可以将对话框附加到 body 元素上,以避免 z-index 问题。 <template><el-dialo

【Unity-Lua】音乐播放器循环滚动播放音乐名

前言:Unity中UI节点 图1 如上所示,一开始本来是打算用ScrollView做的,觉得直接计算对应的文本位置就行,所以没用ScrollRect来做,可以忽略Scroll,Viewport这些名字。如下图:需要在一个背景Image组件上添加上Mask组件来显示固定位置的文本显示。 图2 图3 并且需要在要显示的文本上挂载Content Size Filter组件,但是这儿会有个坑

14,子查询语句嵌套

1.1 查询研发部门的所有员工信息 #步骤1: 查询研发部门的 did SELECT did FROM t_department WHERE dname = '研发部'; #步骤2: 嵌套子查询,查询员工信息 SELECT * FROM t_employee WHERE did = (SELECT did FROM t_department WHERE dname = '研发部');

WebAPI(二)、DOM事件监听、事件对象event、事件流、事件委托、页面加载与滚动事件、页面尺寸事件

文章目录 一、 DOM事件1. 事件监听2. 事件类型(1)、鼠标事件(2)、焦点事件(3)、键盘事件(4)、文本事件 3. 事件对象(1)、获取事件对象(2)、事件对象常用属性 4. 环境对象 this5. 回调函数 二、 DOM事件进阶1. 事件流(1)、 捕获阶段(2)、 冒泡阶段(3)、 阻止冒泡(4) 、阻止元素默认行为(5) 、解绑事件 2. 事件委托3. 其他事件(1)、页面加

NYOJ 16 矩形嵌套

OJ题目 : http://acm.nyist.net/JudgeOnline/problem.php?pid=16 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除