當SwipeRefreshLayout嵌套ViewPager的時候,滑動的時候很不靈敏,而且在左右滑動的往往都會觸發SwipeRefreshLayout的重新整理操作,是以我們需要自定義ViewPager和SwipeRefreshLayout,采用内部攔截法來解決滑動沖突,内部攔截法是指父容器不攔截任何事件,所有的事件都會傳遞給子元素,如果子元素需要此事件就直接消耗掉,否則就交給父容器進行處理。
首先需要重寫子元素的dispatchTouchEvent方法,在ACTION_DOWN事件的時候,請求SwipeRefreshLayout不要攔截,隻有在ACTION_MOVE事件的時候,并且判斷是垂直滑動的話,才請求SwipeRefreshLayout攔截。
class MyViewPager : ViewPager {
private var startX = 0f
private var startY = 0f
private var moveX = 0f
private var moveY = 0f
private var deltaX = 0f
private var deltaY = 0f
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
startX = ev.x
startY = ev.y
ViewCompat.setNestedScrollingEnabled(this,true)
parent.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_MOVE -> {
moveX = ev.x
moveY = ev.y
deltaX = abs(moveX - startX);
deltaY = abs(moveY - startY);
if (deltaX < deltaY) {
parent.requestDisallowInterceptTouchEvent(false)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
}
}
return super.dispatchTouchEvent(ev)
}
}
其次,父容器不能攔截ACTION_DOWN事件,因為ACTION_DOWN事件并不受FLAG_DISALLOW_INTERCEPT這個标記位的控制,是以一旦父容器攔截了ACTION_DOWN事件,所有的事件都無法傳遞到子元素中去了,這樣内部攔截就無法起作用了。
class MyRefreshLayout : SwipeRefreshLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
if (ev.action == MotionEvent.ACTION_DOWN) {
super.onInterceptTouchEvent(ev)
return false
}
return true
}
}