CoordinatorLayout中AppBarLayout滑動抖動問題
問題描述
通過觀察導致抖動的手勢操作,知曉了在快速滑動AppBarLayout部分,手指離開屏幕,滑動還沒有結束的時候,快速反向滑動View,就能夠穩定復現抖動問題。
問題根源
兩個點
- 手指離開屏幕且滑動沒有結束,說明了,此時正處于fling的過程。
- 而滑動View時會產生抖動,說明了,fling這個過程仍然在進行,并沒有因為新的滑動事件出現被取消。
通過翻閱源碼AppBarLayout的fling由OverScroller執行,并且在事件機制中沒有針對MotionEvent.ACTION_CANCEL的滑動停止操作。定位到問題后就好解決了,針對ACTION_CANCEL,獲取scroller并將其終止。
解決方案
class CstAppbarLayout : AppBarLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attr: AttributeSet?) : super(context, attr)
constructor(context: Context, attr: AttributeSet?, defStyleAttr: Int) : super(
context,
attr,
defStyleAttr
)
override fun getBehavior(): CoordinatorLayout.Behavior<AppBarLayout> {
return object : AppBarLayout.BaseBehavior<AppBarLayout>() {
override fun onInterceptTouchEvent(
parent: CoordinatorLayout,
child: AppBarLayout,
ev: MotionEvent
): Boolean {
val result = super.onInterceptTouchEvent(parent, child, ev)
if (ev.action == MotionEvent.ACTION_CANCEL && ev.x == 0f && ev.y == 0f && ev.metaState == 0) {
val scroller = this.javaClass.superclass?.superclass?.getDeclaredField("scroller")
?.apply {
isAccessible = true
}?.get(this) as? OverScroller
// There is an animation in progress. Stop it.
if (scroller != null && !scroller.isFinished) {
scroller.abortAnimation()
}
}
return result
}
}
}
}