您的位置:首页 > 房产 > 建筑 > 网络域名后缀_江苏无锡重要通知_产品推广方案要包含哪些内容_seo怎么去优化

网络域名后缀_江苏无锡重要通知_产品推广方案要包含哪些内容_seo怎么去优化

2025/7/28 13:13:18 来源:https://blog.csdn.net/qq_32035241/article/details/145694255  浏览:    关键词:网络域名后缀_江苏无锡重要通知_产品推广方案要包含哪些内容_seo怎么去优化
网络域名后缀_江苏无锡重要通知_产品推广方案要包含哪些内容_seo怎么去优化

嵌套滑动造成的滑动冲突原理分析

场景复现:

CoordinatorLayout + AppBarLayout + Vertical RecyclerView + Horizontal RecycleView

Horizontal RecycleView 是Vertical RecyclerView的一个子view, CoordinatorLayout 实现了AppBarLayout 和 RecyclerView的协调联动,在向上滑动RecyclerView的时候,会先滑动AppBarLayout,再滑动RecyclerView,问题场景是在点击Horizontal RecycleView,然后向上滑动时,造成了Vertical RecyclerView 滑动,而AppBarLayout 没有滑动。

原理解析:

Behavior的概念

Behavior用于为特定的子 View 定义自定义的交互行为,它通常与 CoordinatorLayout 一起使用,允许开发者在 View 之间创建复杂的滚动、滑动、拖拽等行为。

Behavior 提供了一些关键的回调方法,用于处理事件:

方法描述
onInterceptTouchEvent是否拦截触摸事件。
onTouchEvent处理触摸事件。
onStartNestedScroll是否开始处理嵌套滑动事件。
onNestedScrollAccepted当嵌套滑动被接受时调用。
onNestedPreScroll嵌套滑动事件之前调用,用于消费部分或全部滑动。
onNestedScroll在嵌套滑动期间调用,用于处理滑动的剩余部分。
onStopNestedScroll嵌套滑动结束时调用。
layoutDependsOn定义该 Behavior 是否依赖另一个 View。
onDependentViewChanged当依赖的 View 发生变化时调用(如位置或大小变化)。

CoordinationLayout + AppBarLayout + Vertical RecycleView是如何实现联动的呢?

1.点击AppBarLayout 位置时

​ AppBarLayout 不会消费事件,会将事件传递给CoordinationLayout#onTouchEvent()

if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {// Safe since performIntercept guarantees that// mBehaviorTouchView != null if it returns true//mBehaviorTouchView 就是AppBarLayoutfinal LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();final Behavior b = lp.getBehavior();if (b != null) {handled = b.onTouchEvent(this, mBehaviorTouchView, ev);}}

mBehaviorTouchView 就是AppBarLayout,这时就调用了AppbarLayout#Behavior#onTouchEvent()事件,在这里处理了滑动事件scroll。

2.点击RecyclerView位置滑动时,

首先先进行事件传递,在Action_Down的时候会调用 startNestedScroll(nestedScrollAxis, TYPE_TOUCH),去询问嵌套布局CoordinatorLayout是否可以滑动,嵌套布局怎么来的呢?

if (isNestedScrollingEnabled()) {ViewParent p = mView.getParent();View child = mView;while (p != null) {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;}p = p.getParent();}
}
//ViewParentCompat.classpublic static boolean onStartNestedScroll(@NonNull ViewParent parent, @NonNull View child,@NonNull View target, int nestedScrollAxes, int type) {if (parent instanceof NestedScrollingParent2) {return ...}}

重点看上面的while循环,你会发现它会遍历自己的父view 直到找到实现了NestedScrollingParent2的View ,这里就是指CoordinationLayout了,当找到的时候,将会遍历CoordinationLayout 所有子View 的Behavior是否可以实现嵌套联动的滑动,

// CoordinationLayout.class
public boolean onStartNestedScroll(View child, View target, int axes, int type) {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;}final LayoutParams lp = (LayoutParams) view.getLayoutParams();final Behavior viewBehavior = lp.getBehavior();if (viewBehavior != null) {// 在这里会去调用子view的Behavior去判断是否支持嵌套滚动final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child,target, axes, type);handled |= accepted;// 设置子View是否支持嵌套滚动,指AppBarlayout是否支持lp.setNestedScrollAccepted(type, accepted);} else {lp.setNestedScrollAccepted(type, false);}}return handled;}

设置完是否支持嵌套滚动后,滚动事件就会到Action_Move事件中,这时RecyclerView 就会消费这个事件,主要是以下两行代码:

//RecyclerView.class
//这行代码将x,y传递给CoordinationLayout,然后CoordinationLayout#NestedScroll()方法将x,y传递给AppBarlayout消费
dispatchNestedPreScroll(canScrollHorizontally ? dx : 0,canScrollVertically ? dy : 0,mReusableIntPair, mScrollOffset, TYPE_TOUCH)//消费,最后自己消费剩余的滚动if (consumedX != 0 || consumedY != 0) {dispatchOnScrolled(consumedX, consumedY);}

以上就实现了联动滑动的效果。

问题来了,为什么在Vertical RecyclerView 再加一个Horizontal RecycleView的时候就会是Vertical RecyclerView来消费了呢,原因就是在onStartNestedScroll 通知到AppBarlayout#Behavior时,Horizontal 和Vertical 都通知了一遍,Horizontal时后面通知的,看一下通知后的代码:

//AppBarLayout.class
public boolean onStartNestedScroll(@NonNull CoordinatorLayout parent,@NonNull T child,@NonNull View directTargetChild,View target,int nestedScrollAxes,int type) {// Return true if we're nested scrolling vertically, and we either have lift on scroll enabled// or we can scroll the children.//这里判断了ViewCompat.SCROLL_AXIS_VERTICAL 如果不是VERTICAL的时候就不允许嵌套滑动了final boolean started =(nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0&& (child.isLiftOnScroll() || canScrollChildren(parent, child, directTargetChild));。。。。return started;}

然后Horizontal RecycleView在竖向滑动时是不支持的,所以事件由Vertical RecyclerView滑动,这时呢,嵌套滑动又被拒绝了,只能是

Vertical RecyclerView来响应滑动事件了。

解决方案:

  recyclerView.isNestedScrollingEnabled = false

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com