滑動衝突 有時候 viewpager 嵌套 webview 後,左右滑動衝突,直接消費或者處理攔截導致上下不能滑動,所以需要根據滑動情況判斷處理,只在上下滑動時判斷事件交給子view class ScrollWebView(context: Context, attrs: AttributeSet) ...
滑動衝突
有時候 viewpager 嵌套 webview 後,左右滑動衝突,直接消費或者處理攔截導致上下不能滑動,所以需要根據滑動情況判斷處理,只在上下滑動時判斷事件交給子view
class ScrollWebView(context: Context, attrs: AttributeSet) : WebView(context, attrs) { private var mSlop = 0 private var mDownY = 0f init { mSlop = ViewConfiguration.get(context).scaledTouchSlop } override fun onTouchEvent(event: MotionEvent?): Boolean { when (event?.action) { MotionEvent.ACTION_DOWN -> mDownY = event.y MotionEvent.ACTION_MOVE -> { val off = mDownY - event.y if (abs(off) >= mSlop) { parent.requestDisallowInterceptTouchEvent(true) } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { parent.requestDisallowInterceptTouchEvent(false) } } return super.onTouchEvent(event) } }
舉一反三,很多滑動衝突都可以類似解決,至於是對父容器處理,還是子節點處理,根據情況來定
又比如在 viewpager 下嵌套 Recyclerview,Recyclerview 中又嵌套 viewpager 或者 Recyclerview,此時子 view 左右滑動起了衝突,這個確實不怪業務邏輯複雜了,只能自定義解決了
class NestedViewPager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) { private var x1 = 0f private var y1 = 0f private var isScroll = false override fun dispatchTouchEvent(evt: MotionEvent?): Boolean { evt?.let { when (evt.action) { MotionEvent.ACTION_DOWN -> { x1 = evt.x y1 = evt.y isScroll = false } MotionEvent.ACTION_MOVE -> { // 通知其父控制項不攔截 val x2 = evt.x val y2 = evt.y if (x1 - x2 > 1) { //str = "向右滑" parent.requestDisallowInterceptTouchEvent(true) isScroll = false } else if (x2 - x1 > 1) { //str = "向左滑" parent.requestDisallowInterceptTouchEvent(true) isScroll = false } else if (y1 - y2 > 100) { parent.requestDisallowInterceptTouchEvent(false) //str = "向上滑" isScroll = true } else if (y2 - y1 > 100) { parent.requestDisallowInterceptTouchEvent(false) //str = "向下滑" isScroll = true } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { if (isScroll) { parent.requestDisallowInterceptTouchEvent(false) } else { parent.requestDisallowInterceptTouchEvent(true) } } } } return super.dispatchTouchEvent(evt) } }
依然一頓梭哈解決,但是能不自定義就別自定義,特別是複雜的定義
這種滑動可以適配很多滑動衝突,比如 viewpager 下,嵌套了一個橫向 Recyclerview,此時橫向滑動很容易會觸發 viewpager 的滑動,導致不絲滑,還是一樣的處理
class ScrollRecyclerView(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) { private var x1 = 0f private var y1 = 0f private var isScroll = false override fun dispatchTouchEvent(evt: MotionEvent?): Boolean { evt?.let { when (evt.action) { MotionEvent.ACTION_DOWN -> { x1 = evt.x y1 = evt.y isScroll = false } MotionEvent.ACTION_MOVE -> { // 通知其父控制項不攔截 val x2 = evt.x val y2 = evt.y if (x1 - x2 > 1) { //str = "向右滑" parent.requestDisallowInterceptTouchEvent(true) isScroll = false } else if (x2 - x1 > 1) { //str = "向左滑" parent.requestDisallowInterceptTouchEvent(true) isScroll = false } else if (y1 - y2 > 100) { parent.requestDisallowInterceptTouchEvent(false) //str = "向上滑" isScroll = true } else if (y2 - y1 > 100) { parent.requestDisallowInterceptTouchEvent(false) //str = "向下滑" isScroll = true } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { if (isScroll) { parent.requestDisallowInterceptTouchEvent(false) } else { parent.requestDisallowInterceptTouchEvent(true) } } } } return super.dispatchTouchEvent(evt) } }
只需要換個集成的對象就行,一樣的邏輯,如果對於閾值需要調整,可以使用上面的 scaledTouchSlop
webview卡頓
一般情況下webview不會卡頓,除非用法不但,或者確實由於網頁導致的,如果是網頁導致的只能本地化或者緩存或者預載入處理,但是如果是用法不但就需要自己找原因了
比如有時候代碼寫的爛,界面刷新頻繁導致webview閃爍,就會關閉硬體加速 webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null),但是後來會發現滑動卡頓了,那肯定不能這麼乾
打開硬體加速,優化更新邏輯,問題解決