前言
Android 滑动冲突是 Android 开发中常见的问题。在一个界面中,可能存在多个 View 可以响应滑动事件。如果这些 View 滑动方向一致,则会导致滑动冲突。本文将从原理、使用与优化三个方面,详细介绍 Android 滑动冲突的解决方式。
滑动冲突的原理
Android 的事件分发机制是基于 ViewGroup 的。当用户在屏幕上触摸时,事件会首先传递给最顶层的 ViewGroup。ViewGroup 会根据自己的滑动方向和滑动能力来决定是否拦截事件。如果 ViewGroup 拦截了事件,则事件不会传递给子 View。如果 ViewGroup 没有拦截事件,则事件会传递给子 View。
如果子 View 也需要响应滑动事件,则子 View 需要重写 onTouchEvent() 方法来处理事件。子 View 可以通过 requestDisallowInterceptTouchEvent() 方法来告诉父 ViewGroup 不要拦截事件。
滑动冲突是指两个或多个 View 同时收到滑动事件,导致无法正常滑动。滑动冲突的原因有很多,例如:
- 两个 View 的滑动方向相同,例如 RecyclerView 和 ScrollView 同时滑动。
- 两个 View 的滑动方向不同,但滑动范围重叠,例如 HorizontalScrollView 和 WebView 同时滑动。
解决方法
Android 滑动冲突的主要解决思想有两种:外部拦截法和内部拦截法。
- 外部拦截法:由父 View 拦截事件,然后根据需要将事件传递给子 View。
- 内部拦截法:由子 View 拦截事件,然后根据需要将事件传递给父 View。
外部拦截法
外部拦截法是 Android 默认的滑动冲突解决方式。在这种方式下,父 View 会先拦截事件,然后根据需要将事件传递给子 View。
父 View 可以通过重写 onInterceptTouchEvent() 方法来实现外部拦截法。在 onInterceptTouchEvent() 方法中,我们可以根据事件的类型和位置来判断是否需要拦截事件。如果需要拦截事件,则返回 true,否则返回 false。
class CustomParentView(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {
private var downX: Float = 0F
private var downY: Float = 0F
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
downX = ev.x
downY = ev.y
}
MotionEvent.ACTION_MOVE -> {
val deltaX = ev.x - downX
val deltaY = ev.y - downY
// 根据滑动方向判断是否拦截事件
if (Math.abs(deltaX) > Math.abs(deltaY)) {
}
}
}
.onInterceptTouchEvent(ev)
}
: {
}
}


