滑动冲突
有时候 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),但是后来会发现滑动卡顿了,那肯定不能这么干
打开硬件加速,优化更新逻辑,问题解决