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
|
package com.shuwei.dish.match.dialog
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Rect
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
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.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.core.view.isEmpty
|
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.shuwei.dish.match.R
|
import com.shuwei.dish.match.R
|
||||||
import com.shuwei.dish.match.adapter.SeasoningSearchAdapter
|
import com.shuwei.dish.match.adapter.SeasoningSearchAdapter
|
||||||
@@ -30,7 +31,6 @@ import com.shuwei.dish.match.utils.ext.toast
|
|||||||
*/
|
*/
|
||||||
class SeasoningSelectDialog(
|
class SeasoningSelectDialog(
|
||||||
private val activity: BaseActivity,
|
private val activity: BaseActivity,
|
||||||
private val clickIndex: Int,
|
|
||||||
private val onItemSelected: (item: SeasoningEntity) -> Unit
|
private val onItemSelected: (item: SeasoningEntity) -> Unit
|
||||||
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
||||||
|
|
||||||
@@ -84,18 +84,10 @@ class SeasoningSelectDialog(
|
|||||||
addOnActionSearchListener { searchGoods(this) }
|
addOnActionSearchListener { searchGoods(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecyclerView 初始化及滑动冲突处理
|
// RecyclerView 初始化
|
||||||
binding.recyclerView.run {
|
binding.recyclerView.run {
|
||||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.VERTICAL, false)
|
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.VERTICAL, false)
|
||||||
adapter = this@SeasoningSelectDialog.adapter
|
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 {
|
binding.refreshLayout.run {
|
||||||
@@ -109,11 +101,32 @@ class SeasoningSelectDialog(
|
|||||||
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 弹窗显示时自动加载默认调料列表 */
|
/** 弹窗显示时自动加载默认调料列表,并在 Window.Callback 层提前拦截触摸以解决滑动冲突 */
|
||||||
override fun show() {
|
override fun show() {
|
||||||
super.show()
|
super.show()
|
||||||
pageNo = 1
|
pageNo = 1
|
||||||
getGoodsList()
|
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.dialog.FoodSearchDialog
|
||||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||||
import com.shuwei.dish.match.utils.ActivityManager
|
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.WeightUtil
|
||||||
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
||||||
import com.shuwei.dish.match.utils.ext.gone
|
import com.shuwei.dish.match.utils.ext.gone
|
||||||
@@ -28,6 +27,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "FoodRecognizeActivity"
|
private const val TAG = "FoodRecognizeActivity"
|
||||||
private const val EXTRA_IMAGE_URI = "extra_image_uri"
|
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 EXTRA_SELECTED_ITEM = "extra_selected_item"
|
||||||
const val IS_MANUAL_CANCEL = "isManualCancel"
|
const val IS_MANUAL_CANCEL = "isManualCancel"
|
||||||
|
|
||||||
@@ -44,12 +44,14 @@ class FoodRecognizeActivity : BaseActivity() {
|
|||||||
fun start(
|
fun start(
|
||||||
activity: BaseActivity,
|
activity: BaseActivity,
|
||||||
imageUri: String? = null,
|
imageUri: String? = null,
|
||||||
|
currentWeight: Double = 0.0,
|
||||||
goodsList: ArrayList<CookFoodGoodsEntity> = arrayListOf(),
|
goodsList: ArrayList<CookFoodGoodsEntity> = arrayListOf(),
|
||||||
finishCallback: (Boolean, CookFoodGoodsEntity?) -> Unit = { _, _ -> }
|
finishCallback: (Boolean, CookFoodGoodsEntity?) -> Unit = { _, _ -> }
|
||||||
) {
|
) {
|
||||||
pendingGoodsList = goodsList
|
pendingGoodsList = goodsList
|
||||||
val launchIntent = Intent(activity, FoodRecognizeActivity::class.java).apply {
|
val launchIntent = Intent(activity, FoodRecognizeActivity::class.java).apply {
|
||||||
putExtra(EXTRA_IMAGE_URI, imageUri)
|
putExtra(EXTRA_IMAGE_URI, imageUri)
|
||||||
|
putExtra(EXTRA_CURRENT_WEIGHT, currentWeight)
|
||||||
}
|
}
|
||||||
activity.startActivity(launchIntent) { resultIntent ->
|
activity.startActivity(launchIntent) { resultIntent ->
|
||||||
val isManualCancel = resultIntent?.getBooleanExtra(IS_MANUAL_CANCEL, false) ?: false
|
val isManualCancel = resultIntent?.getBooleanExtra(IS_MANUAL_CANCEL, false) ?: false
|
||||||
@@ -145,6 +147,8 @@ class FoodRecognizeActivity : BaseActivity() {
|
|||||||
if (!imageUri.isNullOrBlank()) {
|
if (!imageUri.isNullOrBlank()) {
|
||||||
binding.ivFoodPhoto.setImageURI(imageUri.toUri())
|
binding.ivFoodPhoto.setImageURI(imageUri.toUri())
|
||||||
}
|
}
|
||||||
|
currentWeight = intent.getDoubleExtra(EXTRA_CURRENT_WEIGHT, 0.0)
|
||||||
|
binding.tvWeight.text = "${currentWeight}g"
|
||||||
|
|
||||||
// 取出内存缓存的食材列表,取用后立即清空
|
// 取出内存缓存的食材列表,取用后立即清空
|
||||||
val goodsList = pendingGoodsList?.also { pendingGoodsList = null }
|
val goodsList = pendingGoodsList?.also { pendingGoodsList = null }
|
||||||
@@ -153,6 +157,7 @@ class FoodRecognizeActivity : BaseActivity() {
|
|||||||
// 默认选中第一项
|
// 默认选中第一项
|
||||||
selectedPosition = 0
|
selectedPosition = 0
|
||||||
list[0].isClicked = true
|
list[0].isClicked = true
|
||||||
|
list[0].useWeight = currentWeight
|
||||||
binding.tvSelectedFood.text = list[0].goodsName ?: "-"
|
binding.tvSelectedFood.text = list[0].goodsName ?: "-"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,40 +227,40 @@ class FoodRecognizeActivity : BaseActivity() {
|
|||||||
* 低于阈值说明食材已被取走,保留上次有效值等待页面关闭
|
* 低于阈值说明食材已被取走,保留上次有效值等待页面关闭
|
||||||
*/
|
*/
|
||||||
private fun registerWeightListener() {
|
private fun registerWeightListener() {
|
||||||
WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
// WeightUtil.addWeightListener(TAG) { address, state, weight ->
|
||||||
if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
// if (address == AddressUtil.ONE && state == WeightUtil.STATE_STABLE) {
|
||||||
runOnUiThread {
|
// runOnUiThread {
|
||||||
currentWeight = weight
|
// currentWeight = weight
|
||||||
binding.tvWeight.run {
|
// binding.tvWeight.run {
|
||||||
if (tag != weight) {
|
// if (tag != weight) {
|
||||||
text = "$weight g"
|
// text = "$weight g"
|
||||||
tag = weight
|
// tag = weight
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (weight >= PrepareCookActivity.WEIGHT_RECOGNIZE_VALUE) {
|
// if (weight >= PrepareCookActivity.WEIGHT_RECOGNIZE_VALUE) {
|
||||||
adapter.items.firstOrNull { it.isClicked }?.let { item ->
|
// adapter.items.firstOrNull { it.isClicked }?.let { item ->
|
||||||
if (pendingWeight != weight) {
|
// if (pendingWeight != weight) {
|
||||||
// 无论增减,均延迟更新,避免手拿物品时的瞬时增重干扰
|
// // 无论增减,均延迟更新,避免手拿物品时的瞬时增重干扰
|
||||||
cancelPendingWeightUpdate()
|
// cancelPendingWeightUpdate()
|
||||||
pendingWeight = weight
|
// pendingWeight = weight
|
||||||
pendingWeightRunnable = Runnable {
|
// pendingWeightRunnable = Runnable {
|
||||||
item.useWeight = weight
|
// item.useWeight = weight
|
||||||
pendingWeightRunnable = null
|
// pendingWeightRunnable = null
|
||||||
}.also { handler.postDelayed(it, 3000) }
|
// }.also { handler.postDelayed(it, 3000) }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消待执行的延迟重量更新任务
|
* 取消待执行的延迟重量更新任务
|
||||||
*/
|
*/
|
||||||
private fun cancelPendingWeightUpdate() {
|
private fun cancelPendingWeightUpdate() {
|
||||||
pendingWeightRunnable?.let { handler.removeCallbacks(it) }
|
// pendingWeightRunnable?.let { handler.removeCallbacks(it) }
|
||||||
pendingWeightRunnable = null
|
// pendingWeightRunnable = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
if (weight < WEIGHT_RECOGNIZE_VALUE) {
|
if (weight < WEIGHT_RECOGNIZE_VALUE) {
|
||||||
showRecognizePage = false
|
showRecognizePage = false
|
||||||
manualCancelFlag = false
|
manualCancelFlag = false
|
||||||
|
lastWeight = weight
|
||||||
FoodRecognizeActivity.close()
|
FoodRecognizeActivity.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -515,9 +516,11 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
lastWeight = currentWeight
|
||||||
FoodRecognizeActivity.start(
|
FoodRecognizeActivity.start(
|
||||||
activity = this,
|
activity = this,
|
||||||
imageUri = lastPhotoUri?.toString(),
|
imageUri = lastPhotoUri?.toString(),
|
||||||
|
currentWeight = currentWeight,
|
||||||
goodsList = ArrayList(foodList),
|
goodsList = ArrayList(foodList),
|
||||||
finishCallback = { isManualCancel, entity ->
|
finishCallback = { isManualCancel, entity ->
|
||||||
Log.d(TAG, "queryFood: isManualCancel=$isManualCancel, entity=${entity.toJsonString()}")
|
Log.d(TAG, "queryFood: isManualCancel=$isManualCancel, entity=${entity.toJsonString()}")
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
|||||||
) {
|
) {
|
||||||
SeasoningSelectDialog(
|
SeasoningSelectDialog(
|
||||||
activity = currentActivity,
|
activity = currentActivity,
|
||||||
clickIndex = position,
|
|
||||||
onItemSelected = callback
|
onItemSelected = callback
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
tools:background="@color/white"
|
tools:background="@color/white"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@@ -15,6 +15,16 @@
|
|||||||
android:layout_marginTop="30dp"
|
android:layout_marginTop="30dp"
|
||||||
android:background="@drawable/shape_gray_dc_5" />
|
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
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
@@ -57,8 +67,10 @@
|
|||||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
android:id="@+id/refreshLayout"
|
android:id="@+id/refreshLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="700dp"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginStart="45dp"
|
||||||
|
android:layout_marginEnd="45dp"
|
||||||
app:srlEnableOverScrollDrag="false">
|
app:srlEnableOverScrollDrag="false">
|
||||||
|
|
||||||
<com.scwang.smart.refresh.header.ClassicsHeader
|
<com.scwang.smart.refresh.header.ClassicsHeader
|
||||||
@@ -69,11 +81,8 @@
|
|||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginStart="45dp"
|
|
||||||
android:layout_marginEnd="45dp"
|
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="15dp"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
android:minHeight="380dp"
|
|
||||||
android:nestedScrollingEnabled="true"
|
android:nestedScrollingEnabled="true"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
|||||||
Reference in New Issue
Block a user