From 3fc54d5f521dc8e926aade6c0ef784111f96b2b6 Mon Sep 17 00:00:00 2001 From: lvmeng <848755140@qq.com> Date: Tue, 21 Apr 2026 15:54:04 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20=E9=87=8D=E6=9E=84=20Scale2VH?= =?UTF-8?q?=20=E4=BD=BF=E7=94=A8=20XML=20=E5=B8=83=E5=B1=80=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=A7=A4=E6=80=BB=E8=A7=88=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - list_type_scale2.xml 替换动态格子为 include list_item_scale22_row,Scale2VH 删除 makeScaleCell/updateScaleCell/makeCellText - list_type_scale1.xml 布局调整为垂直居中,新增 tvName 展示调料名称 - list_type_scale18/22.xml 移除分割线 - SeasoningSelectDialog 搜索列表改为3列,扩充模拟调料数据 Co-Authored-By: Claude Sonnet 4.6 --- .../match/dialog/SeasoningSelectDialog.kt | 22 +- .../dish/match/ui/MasterScaleActivity.kt | 308 ++++++++++-------- app/src/main/res/layout/list_type_scale1.xml | 41 ++- app/src/main/res/layout/list_type_scale18.xml | 10 +- app/src/main/res/layout/list_type_scale2.xml | 29 +- app/src/main/res/layout/list_type_scale22.xml | 10 +- 6 files changed, 241 insertions(+), 179 deletions(-) diff --git a/app/src/main/java/com/shuwei/dish/match/dialog/SeasoningSelectDialog.kt b/app/src/main/java/com/shuwei/dish/match/dialog/SeasoningSelectDialog.kt index bb1503f..396d5e2 100644 --- a/app/src/main/java/com/shuwei/dish/match/dialog/SeasoningSelectDialog.kt +++ b/app/src/main/java/com/shuwei/dish/match/dialog/SeasoningSelectDialog.kt @@ -86,7 +86,7 @@ class SeasoningSelectDialog( // RecyclerView 初始化及滑动冲突处理 binding.recyclerView.run { - layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false) + layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.VERTICAL, false) adapter = this@SeasoningSelectDialog.adapter addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) { @@ -134,19 +134,15 @@ class SeasoningSelectDialog( */ private fun getGoodsList() { // TODO: 联调时注释掉下方模拟数据,取消注释真实接口调用 - val mockData = mutableListOf( - SeasoningEntity(goodsId = "1", goodsName = "精盐"), - SeasoningEntity(goodsId = "2", goodsName = "鸡精"), - SeasoningEntity(goodsId = "3", goodsName = "陈醋"), - SeasoningEntity(goodsId = "4", goodsName = "老抽"), - SeasoningEntity(goodsId = "5", goodsName = "生抽"), - SeasoningEntity(goodsId = "6", goodsName = "花生油"), - SeasoningEntity(goodsId = "7", goodsName = "菜籽油"), - SeasoningEntity(goodsId = "8", goodsName = "胡椒粉"), - SeasoningEntity(goodsId = "9", goodsName = "十三香"), - SeasoningEntity(goodsId = "10", goodsName = "料酒"), - SeasoningEntity(goodsId = "11", goodsName = "白醋") + val nameList = listOf( + "盐", "白砂糖","冰糖", "鸡精", "味精", "陈醋", "老抽", "生抽", "番茄酱", "胡椒粉", "孜然", "十三香", + "料酒", "白醋", "蚝油", "辣椒面", "辣椒酱", "豆瓣酱", "淀粉", "葱", "蒜", "姜", "香菜" ) + val mockData = mutableListOf() + nameList.forEachIndexed { index, name -> + val padString = "${index + 1}".padStart(2, '0') + mockData.add(SeasoningEntity(goodsId = "1000$padString", goodsName = name)) + } loadGoodsList(mockData) // val param = mutableMapOf( diff --git a/app/src/main/java/com/shuwei/dish/match/ui/MasterScaleActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/MasterScaleActivity.kt index 1fcd5ce..ff0e623 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/MasterScaleActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/MasterScaleActivity.kt @@ -3,11 +3,9 @@ package com.shuwei.dish.match.ui import android.annotation.SuppressLint import android.content.Context import android.os.Bundle -import android.view.Gravity import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.TextView +import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -28,6 +26,7 @@ import com.shuwei.dish.match.databinding.ListTypeScale18Binding import com.shuwei.dish.match.databinding.ListTypeScale2Binding import com.shuwei.dish.match.databinding.ListTypeScale22Binding import com.shuwei.dish.match.base.BaseApp +import com.shuwei.dish.match.databinding.ListItemScale22RowBinding import com.shuwei.dish.match.scale.ScaleData import com.shuwei.dish.match.scale.ScaleDeviceConfig import com.shuwei.dish.match.scale.ScaleServiceManager @@ -40,10 +39,10 @@ import com.shuwei.dish.match.utils.ext.toast import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -private const val VIEW_TYPE_SCALE2 = 0 +private const val VIEW_TYPE_SCALE2 = 0 private const val VIEW_TYPE_SCALE22 = 1 private const val VIEW_TYPE_SCALE18 = 2 -private const val VIEW_TYPE_SCALE1 = 3 +private const val VIEW_TYPE_SCALE1 = 3 /** * 主设备秤数据总览页面 @@ -108,24 +107,30 @@ class MasterScaleActivity : BaseActivity() { .groupBy { it.deviceId } .entries .sortedWith(compareBy { entry -> - ScaleDeviceConfig.DEVICE_ORDER.indexOf(entry.key).let { if (it == -1) Int.MAX_VALUE else it } + ScaleDeviceConfig.DEVICE_ORDER.indexOf(entry.key) + .let { if (it == -1) Int.MAX_VALUE else it } }) .map { (deviceId, scales) -> DeviceGroup( deviceId = deviceId, ip = if (deviceId == localId) localIp - else scales.firstOrNull { it.ip.isNotEmpty() }?.ip ?: "", + else scales.firstOrNull { it.ip.isNotEmpty() }?.ip ?: "", scales = scales.map { it.withSlotName() }.sortedBy { it.address } ) } val structureChanged = groups.size != groupList.size || - groups.indices.any { groups[it].deviceId != groupList[it].deviceId } + groups.indices.any { groups[it].deviceId != groupList[it].deviceId } if (structureChanged) { updateList(groups) } else { - groups.forEach { group -> adapter.updateScalesForDevice(group.deviceId, group.scales) } + groups.forEach { group -> + adapter.updateScalesForDevice( + group.deviceId, + group.scales + ) + } } updateStatusBar(scaleMap) @@ -167,8 +172,8 @@ class MasterScaleActivity : BaseActivity() { private inner class DeviceGroupAdapter(data: MutableList) : BaseMultiItemAdapter(data) { - private val scale1VHMap = mutableMapOf() - private val scale2VHMap = mutableMapOf() + private val scale1VHMap = mutableMapOf() + private val scale2VHMap = mutableMapOf() private val scale22VHMap = mutableMapOf() private val scale18VHMap = mutableMapOf() @@ -180,94 +185,164 @@ class MasterScaleActivity : BaseActivity() { } init { - addItemType(VIEW_TYPE_SCALE2, object : BaseMultiItemAdapter.OnMultiItemAdapterListener { - override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = - QuickViewHolder(ListTypeScale2Binding.inflate(LayoutInflater.from(context), parent, false).root) - override fun onBind(holder: QuickViewHolder, position: Int, item: DeviceGroup?) { - item ?: return - val b = ListTypeScale2Binding.bind(holder.itemView) - val vh = Scale2VH(b) - scale2VHMap[item.deviceId] = vh - vh.bind(item) + addItemType( + VIEW_TYPE_SCALE2, + object : + BaseMultiItemAdapter.OnMultiItemAdapterListener { + override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = + QuickViewHolder( + ListTypeScale2Binding.inflate( + LayoutInflater.from(context), + parent, + false + ).root + ) + + override fun onBind( + holder: QuickViewHolder, + position: Int, + item: DeviceGroup? + ) { + item ?: return + val b = ListTypeScale2Binding.bind(holder.itemView) + val vh = Scale2VH(b) + scale2VHMap[item.deviceId] = vh + vh.bind(item) + } + }) + addItemType( + VIEW_TYPE_SCALE22, + object : + BaseMultiItemAdapter.OnMultiItemAdapterListener { + override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = + QuickViewHolder( + ListTypeScale22Binding.inflate( + LayoutInflater.from(context), + parent, + false + ).root + ) + + override fun onBind( + holder: QuickViewHolder, + position: Int, + item: DeviceGroup? + ) { + item ?: return + val b = ListTypeScale22Binding.bind(holder.itemView) + // 每次 onBind 时注册/更新 VH 缓存,后续数据更新直接走 VH,不再触发 notify + val vh = Scale22VH(b) + scale22VHMap[item.deviceId] = vh + vh.bind(item) + } + }) + addItemType( + VIEW_TYPE_SCALE18, + object : + BaseMultiItemAdapter.OnMultiItemAdapterListener { + override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = + QuickViewHolder( + ListTypeScale18Binding.inflate( + LayoutInflater.from(context), + parent, + false + ).root + ) + + override fun onBind( + holder: QuickViewHolder, + position: Int, + item: DeviceGroup? + ) { + item ?: return + val b = ListTypeScale18Binding.bind(holder.itemView) + val vh = Scale18VH(b) + scale18VHMap[item.deviceId] = vh + vh.bind(item) + } + }) + addItemType( + VIEW_TYPE_SCALE1, + object : + BaseMultiItemAdapter.OnMultiItemAdapterListener { + override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = + QuickViewHolder( + ListTypeScale1Binding.inflate( + LayoutInflater.from(context), + parent, + false + ).root + ) + + override fun onBind( + holder: QuickViewHolder, + position: Int, + item: DeviceGroup? + ) { + item ?: return + val b = ListTypeScale1Binding.bind(holder.itemView) + val vh = Scale1VH(b) + scale1VHMap[item.deviceId] = vh + vh.bind(item) + } + }) + onItemViewType { position, list -> + when (list.getOrNull(position)?.deviceId) { + ScaleDeviceConfig.DEVICE_ID_2 -> VIEW_TYPE_SCALE2 + ScaleDeviceConfig.DEVICE_ID_22 -> VIEW_TYPE_SCALE22 + ScaleDeviceConfig.DEVICE_ID_18 -> VIEW_TYPE_SCALE18 + else -> VIEW_TYPE_SCALE1 } - }) - addItemType(VIEW_TYPE_SCALE22, object : BaseMultiItemAdapter.OnMultiItemAdapterListener { - override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = - QuickViewHolder(ListTypeScale22Binding.inflate(LayoutInflater.from(context), parent, false).root) - override fun onBind(holder: QuickViewHolder, position: Int, item: DeviceGroup?) { - item ?: return - val b = ListTypeScale22Binding.bind(holder.itemView) - // 每次 onBind 时注册/更新 VH 缓存,后续数据更新直接走 VH,不再触发 notify - val vh = Scale22VH(b) - scale22VHMap[item.deviceId] = vh - vh.bind(item) - } - }) - addItemType(VIEW_TYPE_SCALE18, object : BaseMultiItemAdapter.OnMultiItemAdapterListener { - override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = - QuickViewHolder(ListTypeScale18Binding.inflate(LayoutInflater.from(context), parent, false).root) - override fun onBind(holder: QuickViewHolder, position: Int, item: DeviceGroup?) { - item ?: return - val b = ListTypeScale18Binding.bind(holder.itemView) - val vh = Scale18VH(b) - scale18VHMap[item.deviceId] = vh - vh.bind(item) - } - }) - addItemType(VIEW_TYPE_SCALE1, object : BaseMultiItemAdapter.OnMultiItemAdapterListener { - override fun onCreate(context: Context, parent: ViewGroup, viewType: Int) = - QuickViewHolder(ListTypeScale1Binding.inflate(LayoutInflater.from(context), parent, false).root) - override fun onBind(holder: QuickViewHolder, position: Int, item: DeviceGroup?) { - item ?: return - val b = ListTypeScale1Binding.bind(holder.itemView) - val vh = Scale1VH(b) - scale1VHMap[item.deviceId] = vh - vh.bind(item) - } - }) - onItemViewType { position, list -> when (list.getOrNull(position)?.deviceId) { - ScaleDeviceConfig.DEVICE_ID_2 -> VIEW_TYPE_SCALE2 - ScaleDeviceConfig.DEVICE_ID_22 -> VIEW_TYPE_SCALE22 - ScaleDeviceConfig.DEVICE_ID_18 -> VIEW_TYPE_SCALE18 - else -> VIEW_TYPE_SCALE1 - }} + } } } // ── ViewHolder: 2个秤 ────────────────────────────────────────────────── private inner class Scale2VH(val b: ListTypeScale2Binding) : RecyclerView.ViewHolder(b.root) { - private lateinit var cells: List @SuppressLint("SetTextI18n") fun bind(group: DeviceGroup) { b.tvDeviceIp.text = "IP:${group.ip.ifEmpty { "未知" }}" b.tvDeviceLabel.text = "设备:${group.deviceId}" - - if (!::cells.isInitialized) { - val cellSize = (resources.displayMetrics.widthPixels - 4 * 4.dp - 10.dp) / 2 - cells = group.scales.take(2).map { scale -> - makeScaleCell(scale, cellSize).also { cell -> - cell.setOnClickListener { - val s = cell.tag as? ScaleData ?: return@setOnClickListener - showTareDialog(deviceId = s.deviceId, ip = s.ip, address = s.address) - } - } + // 两个格子显示秤地址行,隐藏重量/状态(showAddress 通过 visibility 控制) + listOf(b.cell1, b.cell2).forEach { cell -> + cell.tvAddress.visibility = android.view.View.VISIBLE + cell.tvWeight.visibility = android.view.View.VISIBLE + cell.tvState.visibility = android.view.View.VISIBLE + cell.root.setOnClickListener { + val s = cell.root.tag as? ScaleData ?: return@setOnClickListener + showTareDialog(deviceId = s.deviceId, ip = s.ip, address = s.address) } - b.llScaleContainer.removeAllViews() - cells.forEach { b.llScaleContainer.addView(it) } } updateScales(group.scales) } fun updateScales(scales: List) { - if (!::cells.isInitialized) return - scales.take(2).forEachIndexed { i, scale -> - cells.getOrNull(i)?.let { cell -> - cell.tag = scale - updateScaleCell(cell, scale) - } + bindCell(b.cell1, scales.getOrNull(0)) + bindCell(b.cell2, scales.getOrNull(1)) + } + + @SuppressLint("SetTextI18n") + private fun bindCell(cell: ListItemScale22RowBinding, scale: ScaleData?) { + cell.root.tag = scale + cell.tvAddress.run { + text = scale?.let { "秤${it.address}" } ?: "" + textSize = 18f } + cell.tvName.run { + text = if (scale?.address == 1) "净材" else "熟食" + textSize = 22f + } + cell.tvWeight.run { + text = scale?.let { "${it.weight}g" } ?: "" + textSize = 22f + } + cell.tvState.run { + text = stateStr(scale?.state) + textSize = 22f + } + cell.root.updateLayoutParams { height = 400.dp } } } @@ -294,9 +369,18 @@ class MasterScaleActivity : BaseActivity() { alignItems = AlignItems.FLEX_START } b.rvScales.itemAnimator = null - innerAdapter = Seasoning22GridAdapter(largeSize, smallSize, showNameOnly = false, showAddress = true).apply { + innerAdapter = Seasoning22GridAdapter( + largeSize, + smallSize, + showNameOnly = false, + showAddress = true + ).apply { onItemClick = { scale, _ -> - showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address) + showTareDialog( + deviceId = scale.deviceId, + ip = scale.ip, + address = scale.address + ) } } b.rvScales.adapter = innerAdapter @@ -328,11 +412,16 @@ class MasterScaleActivity : BaseActivity() { } b.rvScales.layoutManager = gridLayoutManager b.rvScales.itemAnimator = null - innerAdapter = Seasoning18GridAdapter(showNameOnly = false, showAddress = true).apply { - onItemClick = { scale, _ -> - showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address) + innerAdapter = + Seasoning18GridAdapter(showNameOnly = false, showAddress = true).apply { + onItemClick = { scale, _ -> + showTareDialog( + deviceId = scale.deviceId, + ip = scale.ip, + address = scale.address + ) + } } - } b.rvScales.adapter = innerAdapter } updateScales(group.scales) @@ -374,56 +463,13 @@ class MasterScaleActivity : BaseActivity() { // ── 工具方法 ─────────────────────────────────────────────────────────── private fun stateStr(state: Int?) = when (state) { - WeightUtil.STATE_STABLE -> "稳定" - WeightUtil.STATE_UNSTABLE -> "不稳定" + WeightUtil.STATE_STABLE -> "稳定" + WeightUtil.STATE_UNSTABLE -> "不稳定" WeightUtil.STATE_OVER_WEIGHT -> "超量" null -> "" else -> "$state" } - /** 创建正方形秤格子(用于 Scale2VH 初始化) */ - @SuppressLint("SetTextI18n") - private fun makeScaleCell(scale: ScaleData, cellSize: Int): LinearLayout { - val margin = 2.dp - return LinearLayout(this).apply { - orientation = LinearLayout.VERTICAL - gravity = Gravity.CENTER - layoutParams = LinearLayout.LayoutParams(0, cellSize - margin * 2, 1f) - .also { it.setMargins(margin, margin, margin, margin) } - setPadding(4.dp, 2.dp, 4.dp, 2.dp) - setBackgroundResource(R.drawable.shape_scale_cell) - val baseSize = ((cellSize - margin * 2) / resources.displayMetrics.density).toInt() - addView(makeCellText("秤${scale.address}", (baseSize * 0.16f).coerceIn(9f, 14f).toInt())) - val foodType = if (scale.address == 1) "净材" else "熟食" - addView(makeCellText(foodType, (baseSize * 0.16f).coerceIn(9f, 14f).toInt())) - addView(makeCellText("${scale.weight}g", (baseSize * 0.22f).coerceIn(12f, 20f).toInt(), bold = true)) - addView(makeCellText(stateStr(scale.state), (baseSize * 0.14f).coerceIn(8f, 12f).toInt())) - tag = scale - } - } - - /** 仅更新格子内文字,不重建 view(用于 Scale2VH 数据刷新) */ - @SuppressLint("SetTextI18n") - private fun updateScaleCell(cell: LinearLayout, scale: ScaleData) { - (cell.getChildAt(0) as? TextView)?.text = "秤${scale.address}" - (cell.getChildAt(1) as? TextView)?.text = if (scale.address == 1) "净材" else "熟食" - (cell.getChildAt(2) as? TextView)?.text = "${scale.weight}g" - (cell.getChildAt(3) as? TextView)?.text = stateStr(scale.state) - } - - private fun makeCellText(text: String, spSize: Int, bold: Boolean = false): TextView = - TextView(this).apply { - this.text = text - textSize = spSize.toFloat() - if (bold) setTypeface(null, android.graphics.Typeface.BOLD) - setTextColor(if (bold) getColor(R.color.home_title) else getColor(R.color.home_sub_title)) - layoutParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - gravity = Gravity.CENTER - includeFontPadding = false - } - /** * 弹出清零确认对话框 * @param deviceId 目标设备 ID diff --git a/app/src/main/res/layout/list_type_scale1.xml b/app/src/main/res/layout/list_type_scale1.xml index aedb50a..b980424 100644 --- a/app/src/main/res/layout/list_type_scale1.xml +++ b/app/src/main/res/layout/list_type_scale1.xml @@ -29,48 +29,57 @@ + + - + + + + + diff --git a/app/src/main/res/layout/list_type_scale18.xml b/app/src/main/res/layout/list_type_scale18.xml index 40dcbe2..121e4e5 100644 --- a/app/src/main/res/layout/list_type_scale18.xml +++ b/app/src/main/res/layout/list_type_scale18.xml @@ -32,10 +32,10 @@ android:layout_marginTop="5dp" android:overScrollMode="never" /> - + + + + + diff --git a/app/src/main/res/layout/list_type_scale2.xml b/app/src/main/res/layout/list_type_scale2.xml index 149cd12..845bea2 100644 --- a/app/src/main/res/layout/list_type_scale2.xml +++ b/app/src/main/res/layout/list_type_scale2.xml @@ -25,18 +25,29 @@ android:textSize="14sp" tools:text="设备:device_01" /> - + + android:layout_marginTop="5dp"> - + + + + + diff --git a/app/src/main/res/layout/list_type_scale22.xml b/app/src/main/res/layout/list_type_scale22.xml index 115d424..c56527f 100644 --- a/app/src/main/res/layout/list_type_scale22.xml +++ b/app/src/main/res/layout/list_type_scale22.xml @@ -32,10 +32,10 @@ android:layout_marginTop="5dp" android:overScrollMode="never" /> - + + + + +