From 68f3b2d8906f0cde97dc19d99292009366d614b9 Mon Sep 17 00:00:00 2001 From: dongliang Date: Tue, 28 Apr 2026 21:09:48 +0930 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=8B=E6=8B=89=E6=89=8B=E5=8A=BF?= =?UTF-8?q?=E6=94=B9=E7=94=A8RecyclerView.OnItemTouchListener?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SwipeDownLayout的onInterceptTouchEvent方案仍无法检测到下拉。 改用ViewPager2内部RecyclerView的addOnItemTouchListener, 这是RecyclerView专门提供的触摸观察接口,在RecyclerView 处理事件之前通知listener,保证能看到所有触摸事件。 使用rawY避免坐标系问题,阈值60px(约45dp@120dpi)。 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../com/xiaoqu/watch/ui/home/HomeFragment.kt | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/xiaoqu/watch/ui/home/HomeFragment.kt b/app/src/main/java/com/xiaoqu/watch/ui/home/HomeFragment.kt index 1b911c4..ab40ee4 100644 --- a/app/src/main/java/com/xiaoqu/watch/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/xiaoqu/watch/ui/home/HomeFragment.kt @@ -2,10 +2,12 @@ package com.xiaoqu.watch.ui.home import android.os.Bundle import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.TextView import android.widget.Toast +import androidx.recyclerview.widget.RecyclerView import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle @@ -145,10 +147,9 @@ class HomeFragment : BaseFragment() { showRevokeConfirm() } - // 面板关闭时恢复 ViewPager2 滑动和下拉检测 + // 面板关闭时恢复 ViewPager2 滑动 punchPanel.onDismiss = { binding.viewPager.isUserInputEnabled = true - binding.swipeDownLayout.swipeEnabled = true } } @@ -204,9 +205,8 @@ class HomeFragment : BaseFragment() { /** 展开打卡面板 */ private fun showPunchPanel() { if (punchPanel.isShowing) return - // 禁用 ViewPager2 滑动和下拉检测 + // 禁用 ViewPager2 滑动 binding.viewPager.isUserInputEnabled = false - binding.swipeDownLayout.swipeEnabled = false // 查询考勤状态 punchViewModel.fetchAttendance() // 展开面板 @@ -215,17 +215,51 @@ class HomeFragment : BaseFragment() { // ===== 下拉手势 ===== + /** 触摸起始 Y */ + private var touchStartY = 0f + /** 触摸起始 X */ + private var touchStartX = 0f + /** 本次手势是否已触发过下拉 */ + private var swipeTriggered = false + /** * 初始化下拉手势检测 - * 使用 SwipeDownLayout 在 onInterceptTouchEvent 中检测下拉 - * 比 setOnTouchListener 更可靠——能在事件被子 View 消费前看到 + * 通过 RecyclerView.OnItemTouchListener 监听 ViewPager2 内部触摸 + * 这是最可靠的方式——RecyclerView 在处理事件前会先通知所有 listener */ private fun initSwipeDownDetector() { - binding.swipeDownLayout.onSwipeDown = { - // 只在主页(page=1)且面板未展开时响应 - if (binding.viewPager.currentItem == 1 && !punchPanel.isShowing) { - showPunchPanel() - } + // ViewPager2 内部 RecyclerView 需等布局完成后获取 + binding.viewPager.post { + val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView + recyclerView?.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() { + override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { + when (e.action) { + MotionEvent.ACTION_DOWN -> { + touchStartY = e.rawY + touchStartX = e.rawX + swipeTriggered = false + } + MotionEvent.ACTION_MOVE -> { + if (swipeTriggered) return false + // 只在主页(page=1)且面板未展开时响应 + if (binding.viewPager.currentItem != 1) return false + if (punchPanel.isShowing) return false + + val dy = e.rawY - touchStartY + val dx = e.rawX - touchStartX + // 下滑超过 60px 且方向以垂直为主 + if (dy > 60 && Math.abs(dy) > Math.abs(dx) * 1.5f) { + swipeTriggered = true + showPunchPanel() + } + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + swipeTriggered = false + } + } + return false // 不拦截,ViewPager2 正常工作 + } + }) } }