1.先來看看原始需求,自定義一個(gè)seekbar
關(guān)鍵代碼如下益兄,
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
lastX = event.rawX.toInt()
if (isStartAnimator) {
return false
}
// check finger is touch above slide
if (event.x > slideLeft && event.x < slideBitmap.width + slideLeft) {
slideIsMoving = true
return true
}
}
MotionEvent.ACTION_MOVE -> {
val dx = event.rawX.toInt() - lastX
slideLeft += dx
if (slideLeft < 0) {
slideLeft = 0
}
if (slideLeft > slideBgWidth + margin * 2 - slideBitmap.width) {
slideLeft = slideBgWidth + margin * 2 - slideBitmap.width
}
if (slideIsMoving) {
invalidate()
lastX = event.rawX.toInt()
}
}
MotionEvent.ACTION_UP -> if (slideIsMoving) {
backZero()
slideIsMoving = false
}
else -> {
}
}
return super.onTouchEvent(event)
}
主要流程就是監(jiān)聽用戶觸摸事件节视,當(dāng)用戶點(diǎn)擊在滑塊上面時(shí)彻况,開始處理用戶滑動(dòng)事件(ACTION_DOWN 返回true)背伴,然后計(jì)算用戶滑動(dòng)距離树姨,修改slideLeft 值蹈集,并且調(diào)用invalidate() 刷新界面经宏。在onDraw中根據(jù)slideLeft值犀暑,修改滑塊位置。
2.新的需求是在viewpager中烛恤,此時(shí)我的滑動(dòng)就出現(xiàn)了問題
查看日志如下:
2021-10-15 15:21:56.324 17940-17940/com.example.myapplication I/CustomSeekBar: ACTION_DOWN
2021-10-15 15:21:56.433 17940-17940/com.example.myapplication I/CustomSeekBar: ACTION_MOVE
2021-10-15 15:21:56.450 17940-17940/com.example.myapplication I/CustomSeekBar: ACTION_MOVE
2021-10-15 15:21:56.466 17940-17940/com.example.myapplication I/CustomSeekBar: ACTION_CANCEL
正常情況下應(yīng)該是down- move-up
此時(shí)出現(xiàn)了down-move-cancel
為什么會(huì)這樣呢母怜?
3.咱們帶著問題來分析一下Android的事件分發(fā)處理流程
咱們從activity接收到事件開始,底層的不用在意缚柏。
先來看看activity布局層級(jí)
基于Android SDK 30普通布局
activity布局如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/xml_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager.widget.CustomViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
圖中可以看到activity苹熏,和window其實(shí)都不是view,DecorView才是咱們布局的頂層view币喧,然后到咱們自己的布局上一共已經(jīng)有5層view轨域。從第6層起,剛好就是咱們自己布局文件的根view杀餐。
再來看看activity事件分化流程
以下是一次完整的事件分化處理過程:
請(qǐng)注意干发,viewPager onTouchEvent 默認(rèn)返回true,以下log是我修改代碼后的
2021-10-19 16:48:21.917 4857-4857/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 16:48:21.925 4857-4857/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 16:48:21.926 4857-4857/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 16:48:21.931 4857-4857/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 16:48:21.931 4857-4857/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEvent
2021-10-19 16:48:25.761 4857-4857/com.example.myapplication I/GUOHENG: CustomViewPager onTouchEvent
2021-10-19 16:48:28.814 4857-4857/com.example.myapplication I/GUOHENG: SeekBarActivity onTouchEvent
點(diǎn)擊seekbar時(shí)的事件分化及處理
點(diǎn)擊時(shí)
2021-10-19 17:00:41.669 5464-5464/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:00:41.669 5464-5464/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:00:41.669 5464-5464/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 17:00:41.670 5464-5464/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 17:00:41.670 5464-5464/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEventACTION_DOWN
2021-10-19 17:00:41.670 5464-5464/com.example.myapplication I/GUOHENG: CustomViewPager onTouchEvent
2021-10-19 17:00:41.780 5464-5464/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:00:41.780 5464-5464/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:00:41.780 5464-5464/com.example.myapplication I/GUOHENG: CustomViewPager onTouchEvent
滑動(dòng)seekbar時(shí)的事件分化及處理
滑動(dòng)時(shí)
2021-10-19 17:02:19.707 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:02:19.707 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:02:19.708 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 17:02:19.708 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 17:02:19.708 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEventACTION_DOWN
2021-10-19 17:02:19.778 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:02:19.778 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:02:19.778 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 17:02:19.779 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 17:02:19.779 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEventACTION_MOVE
2021-10-19 17:02:19.779 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity onTouchEvent
2021-10-19 17:02:19.794 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:02:19.794 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:02:19.794 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 17:02:19.795 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 17:02:19.795 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEventACTION_MOVE
2021-10-19 17:02:19.795 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity onTouchEvent
2021-10-19 17:02:19.812 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:02:19.813 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:02:19.813 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager onInterceptTouchEvent
2021-10-19 17:02:19.814 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar dispatchTouchEvent
2021-10-19 17:02:19.814 5577-5577/com.example.myapplication I/GUOHENG: CustomSeekBar onTouchEventACTION_CANCEL
2021-10-19 17:02:19.816 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity onTouchEvent
2021-10-19 17:02:19.828 5577-5577/com.example.myapplication I/GUOHENG: SeekBarActivity dispatchTouchEvent
2021-10-19 17:02:19.828 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager dispatchTouchEvent
2021-10-19 17:02:19.828 5577-5577/com.example.myapplication I/GUOHENG: CustomViewPager onTouchEvent
出現(xiàn)滑動(dòng)沖突原因就是父view將事件搶過去處理了史翘,給我們發(fā)了cancel事件枉长。導(dǎo)致后續(xù)move事件被父view處理,seekbar接收不到后續(xù)事件琼讽。
通過視頻也能看到滑動(dòng)一段距離后必峰,viewpager出現(xiàn)了滑動(dòng)不了的提示。關(guān)鍵代碼如下:
viewpager.java onInterceptTouchEvent()
case MotionEvent.ACTION_MOVE: {
......
if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
Log.v(TAG, "Starting drag!" + mTouchSlop);
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
mLastMotionX = dx > 0
? mInitialMotionX + mTouchSlop : mInitialMotionX - mTouchSlop;
mLastMotionY = y;
setScrollingCacheEnabled(true);
}
viewGroup.java
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
解決沖突:在viewgroup中判斷是否攔截當(dāng)前事件前钻蹬,會(huì)有一個(gè)是否允許攔截的判斷吼蚁,我們可以在滑塊滑動(dòng)時(shí)不讓父親(viewpager)攔截
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_MOVE -> {
Log.i("GUOHENG", "CustomSeekBar onTouchEvent"+ "ACTION_MOVE")
......
......
parent.requestDisallowInterceptTouchEvent(true)
}
此刻就能正常滑動(dòng)了问欠。