fix: 下拉手势改用Activity.dispatchTouchEvent检测
前两种方案(SwipeDownLayout.onInterceptTouchEvent、 RecyclerView.OnItemTouchListener)均无法检测到下拉。 改用Activity.dispatchTouchEvent——触摸事件链最顶层, 在任何View处理之前就能看到所有触摸事件,不可能被拦截。 HomeFragment注册回调,onDestroyView时清理避免泄漏。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package com.xiaoqu.watch.app
|
|||||||
|
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@@ -10,6 +11,7 @@ import com.xiaoqu.watch.service.manager.SystemStateMonitor
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主 Activity(Launcher 模式,单 Activity + 多 Fragment 架构)
|
* 主 Activity(Launcher 模式,单 Activity + 多 Fragment 架构)
|
||||||
@@ -54,6 +56,43 @@ class MainActivity : AppCompatActivity() {
|
|||||||
systemStateMonitor.unregister()
|
systemStateMonitor.unregister()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 下拉手势检测(Activity 级别,不可能被子 View 拦截) =====
|
||||||
|
|
||||||
|
/** 下拉回调(由 HomeFragment 注册) */
|
||||||
|
var onSwipeDown: (() -> Unit)? = null
|
||||||
|
|
||||||
|
private var touchStartY = 0f
|
||||||
|
private var touchStartX = 0f
|
||||||
|
private var swipeTriggered = false
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
||||||
|
// 在事件分发给任何 View 之前,先检测下拉手势
|
||||||
|
if (onSwipeDown != null) {
|
||||||
|
when (ev.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
touchStartY = ev.rawY
|
||||||
|
touchStartX = ev.rawX
|
||||||
|
swipeTriggered = false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
if (!swipeTriggered) {
|
||||||
|
val dy = ev.rawY - touchStartY
|
||||||
|
val dx = ev.rawX - touchStartX
|
||||||
|
// 下滑超过 50px 且垂直方向为主
|
||||||
|
if (dy > 50 && abs(dy) > abs(dx) * 1.5f) {
|
||||||
|
swipeTriggered = true
|
||||||
|
onSwipeDown?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||||
|
swipeTriggered = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物理返回键拦截:
|
* 物理返回键拦截:
|
||||||
* - 已绑定用户 → 开启 NFC 打卡模式(后续模块实现)
|
* - 已绑定用户 → 开启 NFC 打卡模式(后续模块实现)
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ package com.xiaoqu.watch.ui.home
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@@ -124,6 +122,12 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||||||
observePunchState()
|
observePunchState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
// 清理 Activity 下拉回调,避免泄漏
|
||||||
|
(activity as? com.xiaoqu.watch.app.MainActivity)?.onSwipeDown = null
|
||||||
|
}
|
||||||
|
|
||||||
// ===== 打卡面板 =====
|
// ===== 打卡面板 =====
|
||||||
|
|
||||||
/** 初始化打卡面板 */
|
/** 初始化打卡面板 */
|
||||||
@@ -215,51 +219,16 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||||||
|
|
||||||
// ===== 下拉手势 =====
|
// ===== 下拉手势 =====
|
||||||
|
|
||||||
/** 触摸起始 Y */
|
|
||||||
private var touchStartY = 0f
|
|
||||||
/** 触摸起始 X */
|
|
||||||
private var touchStartX = 0f
|
|
||||||
/** 本次手势是否已触发过下拉 */
|
|
||||||
private var swipeTriggered = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化下拉手势检测
|
* 初始化下拉手势检测
|
||||||
* 通过 RecyclerView.OnItemTouchListener 监听 ViewPager2 内部触摸
|
* 在 Activity.dispatchTouchEvent 中检测——触摸事件链最顶层,不会被任何子 View 拦截
|
||||||
* 这是最可靠的方式——RecyclerView 在处理事件前会先通知所有 listener
|
|
||||||
*/
|
*/
|
||||||
private fun initSwipeDownDetector() {
|
private fun initSwipeDownDetector() {
|
||||||
// ViewPager2 内部 RecyclerView 需等布局完成后获取
|
(activity as? com.xiaoqu.watch.app.MainActivity)?.onSwipeDown = {
|
||||||
binding.viewPager.post {
|
// 只在主页(page=1)且面板未展开时响应
|
||||||
val recyclerView = binding.viewPager.getChildAt(0) as? RecyclerView
|
if (binding.viewPager.currentItem == 1 && !punchPanel.isShowing) {
|
||||||
recyclerView?.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
|
showPunchPanel()
|
||||||
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 正常工作
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user