From 979b93c53d820b5271eed4e90da4691878c84044 Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Fri, 8 May 2026 11:10:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(activity):=20=E7=BB=9F=E4=B8=80=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E6=94=B6=E8=B5=B7=E9=80=BB=E8=BE=91=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20RecyclerView=20=E4=BE=A7=E6=BB=91=E6=94=B6=E8=B5=B7?= =?UTF-8?q?=E9=94=AE=E7=9B=98=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shuwei/dish/match/base/BaseActivity.kt | 6 + .../dish/match/ui/CollectedFoodActivity.kt | 12 +- .../dish/match/ui/CookingModeActivity.kt | 2 +- .../dish/match/ui/FoodSearchActivity.kt | 6 +- .../dish/match/ui/PrepareFoodActivity.kt | 134 +++++++++++++----- 5 files changed, 118 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt b/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt index 624dec2..1507785 100644 --- a/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/base/BaseActivity.kt @@ -23,6 +23,7 @@ import com.shuwei.dish.match.net.NetViewModel import com.shuwei.dish.match.db.DbViewModel import com.shuwei.dish.match.ui.InitActivity import com.shuwei.dish.match.utils.ActivityManager +import com.shuwei.dish.match.utils.KeyboardUtil import com.shuwei.dish.match.utils.ext.dp import com.shuwei.dish.match.utils.ext.gone import com.shuwei.dish.match.utils.ext.invisible @@ -65,6 +66,7 @@ open class BaseActivity : AppCompatActivity() { binding.tvRightTime.setPadding(0, verticalPadding, 0, verticalPadding) binding.llTitleBar.gone() binding.ivBack.setOnClickListener { finish() } + binding.root.setOnClickListener { hideKeyboard() } } override fun onDestroy() { @@ -264,4 +266,8 @@ open class BaseActivity : AppCompatActivity() { } } + fun hideKeyboard() { + KeyboardUtil.hideKeyboard(binding.root) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/dish/match/ui/CollectedFoodActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/CollectedFoodActivity.kt index 3d4c8a5..bfba96c 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/CollectedFoodActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/CollectedFoodActivity.kt @@ -47,8 +47,8 @@ class CollectedFoodActivity : BaseActivity() { addOnItemChildClickListener(R.id.ivDelete) { _, _, position -> showDeleteDialog(foodList[position].foodName) } - setOnItemClickListener { _, view, _ -> - KeyboardUtil.hideKeyboard(view) + setOnItemClickListener { _, _, _ -> + hideKeyboard() } } } @@ -84,12 +84,12 @@ class CollectedFoodActivity : BaseActivity() { setContentView(binding.root) setHeaderBackground() binding.root.setOnClickListener { v -> - KeyboardUtil.hideKeyboard(v) + hideKeyboard() } setTitleBar(titleBarAction = { it.visible() it.setOnClickListener { v -> - KeyboardUtil.hideKeyboard(v) + hideKeyboard() } }, titleAction = { it.text = "已采集食材" @@ -156,7 +156,7 @@ class CollectedFoodActivity : BaseActivity() { performSearch { toast(binding.editSearch.hint.toString()) } - KeyboardUtil.hideKeyboard(v) + hideKeyboard() } binding.editSearch.run { addTextChangedListener { @@ -169,7 +169,7 @@ class CollectedFoodActivity : BaseActivity() { performSearch { toast(binding.editSearch.hint.toString()) } - KeyboardUtil.hideKeyboard(v) + hideKeyboard() true } else { false diff --git a/app/src/main/java/com/shuwei/dish/match/ui/CookingModeActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/CookingModeActivity.kt index 2afd5e3..3a89329 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/CookingModeActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/CookingModeActivity.kt @@ -121,7 +121,7 @@ class CookingModeActivity : BaseActivity() { putExtra(FoodSearchActivity.DINNER_TYPE, dinnerType) putExtra(FoodSearchActivity.FOOD_NAME, searchText) } - KeyboardUtil.hideKeyboard(binding.etInputDish) + hideKeyboard() } private fun loadFragment() { diff --git a/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt index dd49bdb..f85ccef 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt @@ -122,7 +122,7 @@ class FoodSearchActivity : BaseActivity() { binding.ivDishSearch.setOnClickListener { v -> pageNo = 1 getInputAndSearch() - KeyboardUtil.hideKeyboard(v) + hideKeyboard() } binding.refreshLayout.setEnableRefresh(true) binding.refreshLayout.setEnableLoadMore(false) @@ -139,13 +139,13 @@ class FoodSearchActivity : BaseActivity() { queryListInfo(foodName!!) } binding.root.setOnClickListener { v -> - KeyboardUtil.hideKeyboard(v) + hideKeyboard() } binding.etInputDish.let { v -> v.addOnActionSearchListener { pageNo = 1 getInputAndSearch() - KeyboardUtil.hideKeyboard( v) + hideKeyboard() } } } diff --git a/app/src/main/java/com/shuwei/dish/match/ui/PrepareFoodActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/PrepareFoodActivity.kt index 7dae87a..d3b9191 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/PrepareFoodActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/PrepareFoodActivity.kt @@ -5,6 +5,8 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.util.Log +import android.view.GestureDetector +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import androidx.activity.addCallback @@ -12,6 +14,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.shuwei.dish.match.R import com.shuwei.dish.match.adapter.FoodMaterialAdapter import com.shuwei.dish.match.base.BaseActivity @@ -39,6 +42,7 @@ import com.shuwei.dish.match.utils.ext.toJsonString import com.shuwei.dish.match.utils.ext.toast import com.shuwei.dish.match.utils.ext.visible import com.yanzhenjie.recyclerview.SwipeMenuItem +import com.yanzhenjie.recyclerview.SwipeRecyclerView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -58,6 +62,7 @@ class PrepareFoodActivity : BaseActivity() { const val HOME = "home" const val WEIGHT_CHANGE_VALUE = 15 const val WEIGHT_RECOGNIZE_VALUE = 10 + /** 主材数量上限 */ const val MATERIAL_COUNT = 3 } @@ -127,6 +132,7 @@ class PrepareFoodActivity : BaseActivity() { WeightUtil.tareTwo(AddressUtil.ONE) delayDismissLoading() } + //binding.root.setOnClickListener { hideKeyboard() } WeightUtil.addWeightListener( weightKey = TAG, getWeight = { address, state, weight -> @@ -145,8 +151,8 @@ class PrepareFoodActivity : BaseActivity() { if (SpTool.cookMode == 1) { // 采集模式:绑定搜索栏交互 - binding.ivDishSearch.setOnClickListener { v -> jumpSearch(v) } - binding.etInputDish.addOnActionSearchListener { jumpSearch(binding.etInputDish) } + binding.ivDishSearch.setOnClickListener { jumpSearch() } + binding.etInputDish.addOnActionSearchListener { jumpSearch() } } binding.btnCook.clickWithDebounce { @@ -189,11 +195,13 @@ class PrepareFoodActivity : BaseActivity() { } private val isTakingPhoto = AtomicBoolean(false) + // 识别成功并查询到数据打开识别页面 private var showRecognizePage = false // 页面可见时允许识别,onPause 后禁止,onResume 后恢复 private var pageVisible = true + // 手动取消标识 private var manualCancelFlag = false private var lastPhotoUri: Uri? = null @@ -213,8 +221,14 @@ class PrepareFoodActivity : BaseActivity() { FoodRecognizeActivity.close() return } - if (!pageVisible || manualCancelFlag || isTakingPhoto.get() || showRecognizePage || abs(lastWeight - weight) <= WEIGHT_CHANGE_VALUE) { - Log.d(TAG, "recognizeFood, lastWeight:$lastWeight, weight:$weight, pageVisible:$pageVisible, manualCancelFlag:$manualCancelFlag, isTakingPhoto:${isTakingPhoto.get()}") + if (!pageVisible || manualCancelFlag || isTakingPhoto.get() || showRecognizePage || abs( + lastWeight - weight + ) <= WEIGHT_CHANGE_VALUE + ) { + Log.d( + TAG, + "recognizeFood, lastWeight:$lastWeight, weight:$weight, pageVisible:$pageVisible, manualCancelFlag:$manualCancelFlag, isTakingPhoto:${isTakingPhoto.get()}" + ) return } showLoading("识别中……") @@ -362,7 +376,7 @@ class PrepareFoodActivity : BaseActivity() { private var isDetailLoaded = false private val list = mutableListOf() private val materialAdapter by lazy { - FoodMaterialAdapter(list = list).apply { + FoodMaterialAdapter(list).apply { onItemClick = { positon -> list.forEachIndexed { index, entity -> entity.isItemClicked = index == positon @@ -371,16 +385,22 @@ class PrepareFoodActivity : BaseActivity() { } addOnItemChildClickListener(R.id.ivClearIcon) { _, _, position -> Log.d(TAG, "onFoodItemClick: ${list[position].toJsonString()}") - if (list[position].isOriginalData) { - list[position].run { - isNewDishType = false - useWeight = 0.0 - isSetFinished = false + val item = list[position] + if (item.isOriginalData) { + deleteRemindDialog("清除确认", "确定清除食材「${item.goodsName}」添加的重量吗?") { + item.run { + isNewDishType = false + useWeight = 0.0 + isSetFinished = false + } + notifyItemChanged(position) } - notifyItemChanged(position) return@addOnItemChildClickListener } - removeFood(position) + + deleteRemindDialog("删除确认", "确定删除食材「${item.goodsName}」吗?") { + removeFood(position) + } } } } @@ -388,36 +408,46 @@ class PrepareFoodActivity : BaseActivity() { /** * RecyclerView初始化 */ + @SuppressLint("ClickableViewAccessibility") private fun initRecyclerView() { - binding.rvMaterialList.run { - layoutManager = - LinearLayoutManager(this@PrepareFoodActivity, LinearLayoutManager.VERTICAL, false) + binding.rvMaterialList.let { + it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) // 仅 isNewDishType=true 的 item 显示侧滑删除菜单(必须在 setAdapter 之前调用) - setSwipeMenuCreator { _, rightMenu, position -> + it.setSwipeMenuCreator { _, rightMenu, position -> if (list.getOrNull(position)?.isNewDishType == true) { rightMenu.addMenuItem(buildDeleteMenuItem()) } } // 点击侧滑菜单项:先关闭菜单,再弹窗确认删除 - setOnItemMenuClickListener { menuBridge, position -> + it.setOnItemMenuClickListener { menuBridge, position -> menuBridge.closeMenu() val item = list.getOrNull(position) ?: return@setOnItemMenuClickListener - CommonDialog(this@PrepareFoodActivity) - .setTitle("删除确认") - .setContent("确定删除食材「${item.goodsName}」吗?") - .setNegativeButton("取消") - .setPositiveButton("删除") { - removeFood(position) - }.show() + deleteRemindDialog("删除确认", "确定删除食材「${item.goodsName}」吗?") { + removeFood(position) + } } // item 点击事件 - setOnItemClickListener { _, position -> + it.setOnItemClickListener { _, position -> materialAdapter.onItemClick?.invoke(position) } - adapter = materialAdapter + handleRvTouchHideKeyboard() + it.adapter = materialAdapter } } + /** + * 删除提醒 + */ + private fun deleteRemindDialog(title: String, content: String, action: () -> Unit) { + CommonDialog(this@PrepareFoodActivity) + .setTitle(title) + .setContent(content) + .setNegativeButton("取消") + .setPositiveButton("确认") { + action() + }.show() + } + /** * 移除菜品 */ @@ -564,9 +594,12 @@ class PrepareFoodActivity : BaseActivity() { activity = this, imageUri = lastPhotoUri?.toString(), currentWeight = currentWeight, - nameScoreList = ArrayList(nameScoreList), + nameScoreList = ArrayList(nameScoreList), finishCallback = { isManualCancel, entity -> - Log.d(TAG, "queryFood: isManualCancel=$isManualCancel, entity=${entity.toJsonString()}") + Log.d( + TAG, + "queryFood: isManualCancel=$isManualCancel, entity=${entity.toJsonString()}" + ) manualCancelFlag = isManualCancel if (isManualCancel) { return@start @@ -582,11 +615,15 @@ class PrepareFoodActivity : BaseActivity() { /** * 跳转食物搜索页(采集模式专用) - * @param v 触发搜索的 View,用于收起键盘 */ - private fun jumpSearch(v: View) { + private fun jumpSearch() { + val searchContent = binding.etInputDish.text.toString().trim() + if (searchContent.isBlank()) { + toast(binding.etInputDish.hint.toString()) + return + } val intent = Intent(this, FoodSearchActivity::class.java).apply { - putExtra(FoodSearchActivity.FOOD_NAME, binding.etInputDish.text.toString().trim()) + putExtra(FoodSearchActivity.FOOD_NAME, searchContent) } startActivity(intent) { foodId = it?.getStringExtra(FoodSearchActivity.FOOD_ID) @@ -599,7 +636,40 @@ class PrepareFoodActivity : BaseActivity() { setSelection(text.length) } } - KeyboardUtil.hideKeyboard(v) + hideKeyboard() + } + + private fun handleRvTouchHideKeyboard() { + val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { + override fun onSingleTapUp(e: MotionEvent): Boolean { + hideKeyboard() + // 返回 false,不消费事件,不影响 item 点击和滚动 + return false + } + }) + binding.rvMaterialList.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() { + private var startX = 0f + private var startY = 0f + + override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { + when (e.action) { + MotionEvent.ACTION_DOWN -> { + startX = e.x + startY = e.y + } + MotionEvent.ACTION_MOVE -> { + val dx = abs(e.x - startX) + val dy = abs(e.y - startY) + // 水平滑动超过阈值时(侧滑手势),关闭键盘 + if (dx > dy && dx > 10) { + hideKeyboard() + } + } + } + gestureDetector.onTouchEvent(e) + return false + } + }) } } \ No newline at end of file