feat(dialog): 调料选择对话框增加滑动冲突处理和重量传递功能
- 修改 dialog_seasoning_select.xml 布局高度为 match_parent 并添加标题文本 - 调整 SmartRefreshLayout 高度限制并移除 RecyclerView 内边距 - 在 FoodRecognizeActivity 中新增 currentWeight 参数传递机制 - 移除 WeightUtil 监听器相关代码并初始化当前重量值 - 在 PrepareCookActivity 中传递当前重量到识别页面 - 从 SeasoningConfigFragment 和 SeasoningSelectDialog 中移除无用参数 - 添加 Window.Callback 触摸事件拦截解决 RecyclerView 滑动冲突 - 实现触摸点位置检测动态控制 BottomSheet 拖拽行为
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
package com.shuwei.dish.match.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.SeasoningSearchAdapter
|
||||
@@ -30,7 +31,6 @@ import com.shuwei.dish.match.utils.ext.toast
|
||||
*/
|
||||
class SeasoningSelectDialog(
|
||||
private val activity: BaseActivity,
|
||||
private val clickIndex: Int,
|
||||
private val onItemSelected: (item: SeasoningEntity) -> Unit
|
||||
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
||||
|
||||
@@ -84,18 +84,10 @@ class SeasoningSelectDialog(
|
||||
addOnActionSearchListener { searchGoods(this) }
|
||||
}
|
||||
|
||||
// RecyclerView 初始化及滑动冲突处理
|
||||
// RecyclerView 初始化
|
||||
binding.recyclerView.run {
|
||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.VERTICAL, false)
|
||||
adapter = this@SeasoningSelectDialog.adapter
|
||||
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(rv, dx, dy)
|
||||
// 解决 RecyclerView 与 SmartRefreshLayout 滑动冲突
|
||||
val topRowVerticalPosition = if (rv.isEmpty()) 0 else rv.getChildAt(0).top
|
||||
binding.refreshLayout.setNestedScrollingEnabled(topRowVerticalPosition >= 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
binding.refreshLayout.run {
|
||||
@@ -109,11 +101,32 @@ class SeasoningSelectDialog(
|
||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
||||
}
|
||||
|
||||
/** 弹窗显示时自动加载默认调料列表 */
|
||||
/** 弹窗显示时自动加载默认调料列表,并在 Window.Callback 层提前拦截触摸以解决滑动冲突 */
|
||||
override fun show() {
|
||||
super.show()
|
||||
pageNo = 1
|
||||
getGoodsList()
|
||||
// Window.Callback.dispatchTouchEvent 在整个 View 树的 onInterceptTouchEvent 之前执行,
|
||||
// 是最早能感知触摸的时机。在此处判断触摸点位置来控制 behavior.isDraggable,
|
||||
// 从而确保 BottomSheetBehavior 在 CoordinatorLayout.onInterceptTouchEvent 时
|
||||
// 已经是禁用状态,不会拦截列表区域的滑动手势。
|
||||
val originalCallback = window?.callback ?: return
|
||||
window?.callback = object : Window.Callback by originalCallback {
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val rect = Rect()
|
||||
binding.refreshLayout.getGlobalVisibleRect(rect)
|
||||
// 触摸点落在列表区域内则禁止 BottomSheet 拖拽
|
||||
behavior.isDraggable = !rect.contains(event.rawX.toInt(), event.rawY.toInt())
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
behavior.isDraggable = true
|
||||
}
|
||||
}
|
||||
return originalCallback.dispatchTouchEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.shuwei.dish.match.databinding.ActivityFoodRecognizeBinding
|
||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.utils.ActivityManager
|
||||
import com.shuwei.dish.match.utils.AddressUtil
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
@@ -28,6 +27,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
companion object {
|
||||
private const val TAG = "FoodRecognizeActivity"
|
||||
private const val EXTRA_IMAGE_URI = "extra_image_uri"
|
||||
private const val EXTRA_CURRENT_WEIGHT = "extra_current_weight"
|
||||
const val EXTRA_SELECTED_ITEM = "extra_selected_item"
|
||||
const val IS_MANUAL_CANCEL = "isManualCancel"
|
||||
|
||||
@@ -44,12 +44,14 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
fun start(
|
||||
activity: BaseActivity,
|
||||
imageUri: String? = null,
|
||||
currentWeight: Double = 0.0,
|
||||
goodsList: ArrayList<CookFoodGoodsEntity> = arrayListOf(),
|
||||
finishCallback: (Boolean, CookFoodGoodsEntity?) -> Unit = { _, _ -> }
|
||||
) {
|
||||
pendingGoodsList = goodsList
|
||||
val launchIntent = Intent(activity, FoodRecognizeActivity::class.java).apply {
|
||||
putExtra(EXTRA_IMAGE_URI, imageUri)
|
||||
putExtra(EXTRA_CURRENT_WEIGHT, currentWeight)
|
||||
}
|
||||
activity.startActivity(launchIntent) { resultIntent ->
|
||||
val isManualCancel = resultIntent?.getBooleanExtra(IS_MANUAL_CANCEL, false) ?: false
|
||||
@@ -145,6 +147,8 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
if (!imageUri.isNullOrBlank()) {
|
||||
binding.ivFoodPhoto.setImageURI(imageUri.toUri())
|
||||
}
|
||||
currentWeight = intent.getDoubleExtra(EXTRA_CURRENT_WEIGHT, 0.0)
|
||||
binding.tvWeight.text = "${currentWeight}g"
|
||||
|
||||
// 取出内存缓存的食材列表,取用后立即清空
|
||||
val goodsList = pendingGoodsList?.also { pendingGoodsList = null }
|
||||
@@ -153,6 +157,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
// 默认选中第一项
|
||||
selectedPosition = 0
|
||||
list[0].isClicked = true
|
||||
list[0].useWeight = currentWeight
|
||||
binding.tvSelectedFood.text = list[0].goodsName ?: "-"
|
||||
}
|
||||
}
|
||||
@@ -222,40 +227,40 @@ class FoodRecognizeActivity : BaseActivity() {
|
||||
* 低于阈值说明食材已被取走,保留上次有效值等待页面关闭
|
||||
*/
|
||||
private fun registerWeightListener() {
|
||||
WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||
if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
||||
runOnUiThread {
|
||||
currentWeight = weight
|
||||
binding.tvWeight.run {
|
||||
if (tag != weight) {
|
||||
text = "$weight g"
|
||||
tag = weight
|
||||
}
|
||||
}
|
||||
if (weight >= PrepareCookActivity.WEIGHT_RECOGNIZE_VALUE) {
|
||||
adapter.items.firstOrNull { it.isClicked }?.let { item ->
|
||||
if (pendingWeight != weight) {
|
||||
// 无论增减,均延迟更新,避免手拿物品时的瞬时增重干扰
|
||||
cancelPendingWeightUpdate()
|
||||
pendingWeight = weight
|
||||
pendingWeightRunnable = Runnable {
|
||||
item.useWeight = weight
|
||||
pendingWeightRunnable = null
|
||||
}.also { handler.postDelayed(it, 3000) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||
// if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
||||
// runOnUiThread {
|
||||
// currentWeight = weight
|
||||
// binding.tvWeight.run {
|
||||
// if (tag != weight) {
|
||||
// text = "$weight g"
|
||||
// tag = weight
|
||||
// }
|
||||
// }
|
||||
// if (weight >= PrepareCookActivity.WEIGHT_RECOGNIZE_VALUE) {
|
||||
// adapter.items.firstOrNull { it.isClicked }?.let { item ->
|
||||
// if (pendingWeight != weight) {
|
||||
// // 无论增减,均延迟更新,避免手拿物品时的瞬时增重干扰
|
||||
// cancelPendingWeightUpdate()
|
||||
// pendingWeight = weight
|
||||
// pendingWeightRunnable = Runnable {
|
||||
// item.useWeight = weight
|
||||
// pendingWeightRunnable = null
|
||||
// }.also { handler.postDelayed(it, 3000) }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消待执行的延迟重量更新任务
|
||||
*/
|
||||
private fun cancelPendingWeightUpdate() {
|
||||
pendingWeightRunnable?.let { handler.removeCallbacks(it) }
|
||||
pendingWeightRunnable = null
|
||||
// pendingWeightRunnable?.let { handler.removeCallbacks(it) }
|
||||
// pendingWeightRunnable = null
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -196,6 +196,7 @@ class PrepareCookActivity : BaseActivity() {
|
||||
if (weight < WEIGHT_RECOGNIZE_VALUE) {
|
||||
showRecognizePage = false
|
||||
manualCancelFlag = false
|
||||
lastWeight = weight
|
||||
FoodRecognizeActivity.close()
|
||||
return
|
||||
}
|
||||
@@ -515,9 +516,11 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}
|
||||
)
|
||||
}
|
||||
lastWeight = currentWeight
|
||||
FoodRecognizeActivity.start(
|
||||
activity = this,
|
||||
imageUri = lastPhotoUri?.toString(),
|
||||
currentWeight = currentWeight,
|
||||
goodsList = ArrayList(foodList),
|
||||
finishCallback = { isManualCancel, entity ->
|
||||
Log.d(TAG, "queryFood: isManualCancel=$isManualCancel, entity=${entity.toJsonString()}")
|
||||
|
||||
@@ -136,7 +136,6 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
||||
) {
|
||||
SeasoningSelectDialog(
|
||||
activity = currentActivity,
|
||||
clickIndex = position,
|
||||
onItemSelected = callback
|
||||
).show()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
tools:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
@@ -15,6 +15,16 @@
|
||||
android:layout_marginTop="30dp"
|
||||
android:background="@drawable/shape_gray_dc_5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSheetName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
android:textColor="@color/black333"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold"
|
||||
android:text="调料检索" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
@@ -57,8 +67,10 @@
|
||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||
android:id="@+id/refreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="700dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginStart="45dp"
|
||||
android:layout_marginEnd="45dp"
|
||||
app:srlEnableOverScrollDrag="false">
|
||||
|
||||
<com.scwang.smart.refresh.header.ClassicsHeader
|
||||
@@ -69,11 +81,8 @@
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="45dp"
|
||||
android:layout_marginEnd="45dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:minHeight="380dp"
|
||||
android:nestedScrollingEnabled="true"
|
||||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
|
||||
Reference in New Issue
Block a user