ScrollView嵌套RecyclerView滑动冲突解决

ScrollView嵌套RecyclerView滑动冲突解决

2023年7月13日发(作者:)

ScrollView嵌套RecyclerView滑动冲突解决最近发现⾃⼰负责的项⽬中,有使⽤ ScrollView 嵌套 RecyclerView 的地⽅,但是没有做任何针对滑动冲突的处理,于是就想看下为什么没有做这个处理,便进⾏了如下测试,发现了⼏个奇怪的问题。测试场景:页⾯内容包括类似 HeaderView 的部分 + RecyclerView列表部分,布局是垂直⽅向,此处列表之上的布局内容并不是以 headeradd到RecyclerView上的。测试结果:1. 在部分⼿机上,如果列表内容过少,只会造成很⼩程度的滑动,这种滑动冲突是没法察觉到的,很容易忽略滑动冲突;2. 在部分⼿机上,列表内容过多时,滑动 RecyclerView 部分,会很卡顿,滑动 仅ScrollView 部分,很顺畅,笔者试过Vivio x5plus 5.0系统会出现这样的情况;3. 在部分⼿机上,不管列表内容多少,当滑动时,只有 RecyclerView部分滑动,Header顶部布局内容固定,没有⼀起滑动,Redmi Note46.0系统则会出现这种结果。⼀般地,对于第三种结果,⼀看就知道不是我们想要的结果,这种便是滑动冲突,但是不仔细时,均会因前两种结果⽽忽略了滑动冲突。现在,将针对以上的滑动冲突提供⼏种不同的解决⽅法。⽅式⼀:禁⽌RecyclerView滑动最直接的⽅式是将布局管理器中判断可滑动的⽅法,直接返回false,代码如下:LinearLayoutManager layoutManager = new LinearLayoutManager(context) { @Override public boolean canScrollVertically() { // 直接禁⽌垂直滑动 return false; }}源码实现:/** * @return true if {@link #getOrientation()} is {@link #VERTICAL} */@Overridepublic boolean canScrollVertically() { return mOrientation == VERTICAL;}另⼀种⽅式便是重写布局管理器,以 LinearLayoutManager 为例,重写滑动⽅法,并且通过外部⼿动设置,代码如下:public class ScrollLinearLayoutManager extends LinearLayoutManager {private boolean isScrollEnable = true;public ScrollLinearLayoutManager(Context context) { super(context);}public ScrollLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout);}public ScrollLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes);}@Overridepublic boolean canScrollVertically() { return isScrollEnable && ollVertically();}/** * 设置 RecyclerView 是否可以垂直滑动 * @param isEnable */public void setScrollEnable(boolean isEnable) { llEnable = isEnable;}}⽅式⼆:通过View事件分发机制,进⾏事件拦截重写⽗控件,让⽗控件 ScrollView 直接拦截滑动事件,不向下分发给 RecyclerView,具体是定义⼀个ScrollView⼦类,重写其onInterceptTouchEvent()⽅法,代码如下:public class ScrollInterceptScrollView extends ScrollView {private int downX, downY;private int mTouchSlop;public ScrollInterceptScrollView(Context context) { this(context, null);}public ScrollInterceptScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0);}public ScrollInterceptScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mTouchSlop = (context).getScaledTouchSlop();}@TargetApi(N_OP)public ScrollInterceptScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mTouchSlop = (context).getScaledTouchSlop();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { int action = ion(); switch (action) { case _DOWN: downX = (int) X(); downY = (int) Y(); break; case _MOVE: int moveY = (int) Y(); // 判断是否滑动,若滑动就拦截事件 if ((moveY - downY) > mTouchSlop) { return true; } break; default: break; } return rceptTouchEvent(ev);}}但是,现在⼜出现了另⼀个问题,笔者使⽤上述两种⽅式,不管是直接禁⽌RecyclerView不可滑动,重写LinearLayoutManager,还是直接拦截滑动事件不分发给RecyclerView,Vivio x5plus 5.0⼿机确实不会卡顿,但是 Redmi Note4 6.0上,RecyclerView会出现显⽰不全的情况。针对这种情形,使⽤⽹上的⽅法⼀种是使⽤ RelativeLayout 包裹 RecyclerView 并设置属性:android:descendantFocusability="blocksDescendants"代码如下:

这种⽅式⽹上的说法是主要针对 6.0⼿机的解决⽅式,在 Redmi Note4 6.0⼿机上确实可以显⽰完全,Vivio 5.0⼿机不会出现这种情况,仅需处理卡顿问题。Note: android:descendantFocusability="blocksDescendants",该属>性是当⼀个view 获取焦点时,定义 ViewGroup 和其⼦控件直接的关系,常⽤来>解决⽗控件的焦点或者点击事件被⼦空间获取。属性的值有三种:beforeDescendants: ViewGroup会优先其⼦控件获取焦点afterDescendants: ViewGroup只有当其⼦控件不需要获取焦点时才获取焦点blocksDescendants: ViewGroup会覆盖⼦类控件⽽直接获得焦点⽅式三:使⽤ NestedScrollView 嵌套 RecyclerView这种⽅式较之 ScrollView 嵌套 RecyclerView 更简单,不⽤复写很多。布局⽂件如下: NestedScrollView 嵌套 RecyclerView也会出现 滑动卡顿问题,这是只需要禁⽌ RecyclerView 的滑动即可,通过在 xml 中给 RecyclerView添加 android:nestedScrollingEnabled="false" 或者 直接设置 tedScrollingEnabled(false); 即可解决。最后,还要说⼀下,不管是 ScrollView 还是 NestedScrollView 嵌套 RecyclerView 都会存在这样的问题:1. 初次进⼊页⾯,RecyclerView会直接显⽰在页⾯顶部,⽽不是 Header 部分,这是因为这种嵌套页⾯焦点被 RecyclerView 获取。解决⽅式:给 Header 部分View 添加属性:android:focusable="true"android:focusableInTouchMode="true"2. 两种⽅式嵌套,RecyclerView 会失去复⽤性,在数据量很⼤时,会存在内存消耗问题。解决⽅式之⼀:若Header部分是简单布局,可将其作为 RecyclerView 的头部部分,这种⽅式很常见。若Header部分⽐较复杂,如何保证 RecyclerView 的复⽤性,待尝试。

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689217693a222487.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信