Android NestedScrollView(RecyclerView)与嵌套View的滑动冲突

552 阅读1分钟

NestedScrollView(RecyclerView)与EditText滑动冲突

NestedScrollView(RecyclerView) 可滑动,但嵌套的 EditText 不可滑动。

原因分析

NestedScrollView(RecyclerView)把事件消费掉了,没有传递到EditText,从而导致没法使得 EditText 响应事件

解决思路

解决滑动冲突不难,核心思想就是要根据滑动的方向以及业务的场景来判断此时应该由哪个View处理滑动事件

  • 内部拦截法,当满足操作的时候,就通知父view不要拦截,其他情况,正常走父view的滑动。
  • 当触摸的是EditText & 当前EditText多行可滚动时,则将事件交给EditText处理,即进行滚动
  • 否则将事件交由其父类处理,即交给NestedScrollView(RecyclerView)进行滚动。

解决方案

复写EditTextonTouch()并 采用 requestDisallowInterceptTouchEvent(true)进行触碰事件拦截。

@SuppressLint("ClickableViewAccessibility")
private val onTouchListener = OnTouchListener { v, event ->
    // 当触摸的是EditText & 当前EditText可滚动时,则将事件交给EditText处理
    val canVerticalScroll = viewBinding.etFeedback.lineCount > viewBinding.etFeedback.maxLines
    if (v.id == R.id.etFeedback && canVerticalScroll) {
        v.parent.requestDisallowInterceptTouchEvent(true)
        // 否则将事件交由其父类处理
        if (event.action == MotionEvent.ACTION_UP) {
            v.parent.requestDisallowInterceptTouchEvent(false)
        }
    }
    false
}

NestedScrollView与RecyclerView滑动冲突

NestedScrollView 可滑动,但嵌套的 RecyclerView 不可滑动。

解决思路

  • 当触摸的是RecyclerView & 当前RecyclerView可滚动时,则将事件交给RecyclerView处理,即进行滚动
  • 否则将事件交由其父类处理,即交给NestedScrollView进行滚动。

解决方案

复写RecyclerViewonTouch()并 采用 requestDisallowInterceptTouchEvent(true)进行触碰事件拦截。

// 解决NestedScrollView RecycleView 嵌套 滑动冲突,RecycleView内容展示不全 问题
binding.rv.setOnTouchListener { v, event ->
    // RecyclerView & 当前RecyclerView可滚动时,则将事件交给RecyclerView处理
    val itemCount = binding.rv.adapter?.itemCount ?: 0
    val canScroll = itemCount > binding.rv.childCount
    if (v.id == R.id.rv && canScroll) {
        v.parent.requestDisallowInterceptTouchEvent(true)
        // 否则将事件交由其父类处理
        if (event.action == MotionEvent.ACTION_UP) {
            v.parent.requestDisallowInterceptTouchEvent(false)
        }
    }
    false
}