refactor(adapter): 合并 Scale18/22GridAdapter 为 Seasoning18/22GridAdapter,统一支持调料配置和秤总览双模式

- ScaleData 新增可空 name 字段,用于承载调料名称
- Seasoning18/22GridAdapter 改用 ScaleData,新增 showNameOnly 参数区分页面模式
- showNameOnly=true(调料配置):仅显示名称,无名称显示"-"
- showNameOnly=false(秤总览):显示名称+重量+状态,无名称显示秤地址编号
- update() 恢复差量更新逻辑,避免 submitList 动画期间点击失效
- MasterScaleActivity、SlaveActivity 改用新 Adapter,删除旧 Scale18/22GridAdapter
- 删除 Scale22GridActivity 及其布局和 Manifest 注册
- list_item_scale22_row.xml 中 tvAddr 重命名为 tvName

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 11:59:59 +08:00
co-authored by Claude Sonnet 4.6
parent ffdf364ee8
commit a81e914b63
12 changed files with 197 additions and 563 deletions
-5
View File
@@ -106,11 +106,6 @@
android:theme="@style/Theme.DishMatch.NoSplash" android:theme="@style/Theme.DishMatch.NoSplash"
android:screenOrientation="portrait" android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" /> tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name="com.shuwei.dish.match.ui.Scale22GridActivity"
android:theme="@style/Theme.DishMatch.NoSplash"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity <activity
android:name="com.shuwei.dish.match.ui.FoodRecognizeActivity" android:name="com.shuwei.dish.match.ui.FoodRecognizeActivity"
android:theme="@style/Theme.DishMatch.NoSplash" android:theme="@style/Theme.DishMatch.NoSplash"
@@ -1,139 +0,0 @@
package com.shuwei.dish.match.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.annotation.SuppressLint
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.shuwei.dish.match.R
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.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp
/**
* 18个秤的网格 Adapter
* 使用 GridLayoutManager6列)排列,第1行格子 margin 较大(视觉更小),第2-3行 margin 较小
* 点击格子触发清零回调
*/
class Scale18GridAdapter : BaseQuickAdapter<ScaleData, Scale18GridAdapter.VH>(mutableListOf()) {
inner class VH(val b: ListItemScale22RowBinding) : QuickViewHolder(b.root)
/** 用 address=0 的哨兵表示空位 */
private val empty = ScaleData("", 0, 0.0, -1, 0)
/** 当前高亮的格子位置,-1 表示无高亮 */
private var highlightedPosition: Int = -1
/** 点击回调,在 onCreateViewHolder 中绑定,不受 notifyItemChanged 影响 */
var onItemClick: ((ScaleData) -> Unit)? = null
/**
* 按 SCALE_ORDER_18 顺序更新数据,空位用哨兵填充
* 只更新显示字段有变化的格子,避免全量刷新
*/
fun update(newList: List<ScaleData?>) {
val filled = newList.map { it ?: empty }
if (items.isEmpty()) {
submitList(filled)
} else {
filled.forEachIndexed { i, scale ->
val cur = items.getOrNull(i)
if (cur == null || cur.address != scale.address || cur.weight != scale.weight || cur.state != scale.state) {
set(i, scale)
}
}
}
}
/**
* 将 ScaleData 列表按 SCALE_ORDER_18 重排后调用 update
*/
fun updateByAddress(scales: List<ScaleData>) {
val byAddress = scales.associateBy { it.address }
update(ScaleDeviceConfig.SCALE_ORDER_18.map { byAddress[it] })
}
/** 前6个位置为第1行(viewType=0margin大),其余为第2-3行(viewType=1margin小) */
override fun getItemViewType(position: Int, list: List<ScaleData>) = if (position < 6) 0 else 1
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val b = ListItemScale22RowBinding.inflate(LayoutInflater.from(context), parent, false)
// 第1行 margin=12dp(格子视觉更小),第2-3行 margin=2dp
val margin = if (viewType == 0) 12.dp else 2.dp
val screenWidth = parent.resources.displayMetrics.widthPixels
val cellSize = (screenWidth - 6 * margin * 2 - 10.dp) / 6
b.root.layoutParams = (b.root.layoutParams as ViewGroup.MarginLayoutParams).also {
it.width = cellSize
it.height = cellSize
// 第1行:顶部间距为0,底部间距2dp,左右保持原有 margin
if (viewType == 0) it.setMargins(margin, 0, margin, 2.dp)
else it.setMargins(margin, margin, margin, margin)
}
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvAddr.textSize = (baseSp * 0.16f).coerceIn(9f, 14f)
b.tvWeight.textSize = (baseSp * 0.22f).coerceIn(12f, 20f)
b.tvState.textSize = (baseSp * 0.14f).coerceIn(8f, 12f)
val vh = VH(b)
// 在 ViewHolder 创建时绑定点击,只执行一次,不受 notifyItemChanged 重绑定影响
b.root.setOnClickListener {
val pos = vh.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
items.getOrNull(pos)?.takeIf { it.address != 0 }?.let { onItemClick?.invoke(it) }
}
}
return vh
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: VH, position: Int, item: ScaleData?) {
val valid = (item?.address ?: 0) != 0
holder.b.tvAddr.text = if (valid) "${item!!.address}" else ""
holder.b.tvWeight.text = if (valid) "${item!!.weight}g" else ""
holder.b.tvState.text = if (valid) stateStr(item!!.state) else ""
// 高亮格子:红底白字;其余恢复默认
if (position == highlightedPosition) {
holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
holder.b.tvAddr.setTextColor(white)
holder.b.tvWeight.setTextColor(white)
holder.b.tvState.setTextColor(white)
} else {
holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
holder.b.tvAddr.setTextColor(normal)
holder.b.tvWeight.setTextColor(normal)
holder.b.tvState.setTextColor(normal)
}
}
/**
* 高亮指定位置的格子(红底白字),同时清除上一个高亮
* @param position 要高亮的格子索引
*/
fun highlightPosition(position: Int) {
val prev = highlightedPosition
highlightedPosition = position
if (prev >= 0) notifyItemChanged(prev)
if (position >= 0) notifyItemChanged(position)
}
/**
* 清除所有高亮,恢复默认样式
*/
fun clearHighlight() {
highlightPosition(-1)
}
private fun stateStr(state: Int) = when (state) {
WeightUtil.STATE_STABLE -> "稳定"
WeightUtil.STATE_UNSTABLE -> "不稳定"
WeightUtil.STATE_OVER_WEIGHT -> "超量"
else -> "$state"
}
}
@@ -1,141 +0,0 @@
package com.shuwei.dish.match.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.R
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.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp
/**
* 22个秤的网格 Adapter
* 使用 FlexboxLayoutManager 按列排列,前4个格子较大(对应物理上的大秤),其余较小
* 点击格子触发清零回调
*
* @param largeSize 前4个大格子的尺寸(px
* @param smallSize 其余小格子的尺寸(px
*/
class Scale22GridAdapter(
private val largeSize: Int,
private val smallSize: Int
) : BaseQuickAdapter<ScaleData, Scale22GridAdapter.VH>(mutableListOf()) {
inner class VH(val b: ListItemScale22RowBinding) : QuickViewHolder(b.root)
/** 用 address=0 的哨兵表示空位 */
private val empty = ScaleData("", 0, 0.0, -1, 0)
/** 当前高亮的格子位置,-1 表示无高亮 */
private var highlightedPosition: Int = -1
/** 点击回调,在 onCreateViewHolder 中绑定,不受 notifyItemChanged 影响 */
var onItemClick: ((ScaleData) -> Unit)? = null
/**
* 按 SCALE_ORDER_22 顺序更新数据,空位用哨兵填充
* 只更新显示字段有变化的格子,避免全量刷新
*/
fun update(newList: List<ScaleData?>) {
val filled = newList.map { it ?: empty }
if (items.isEmpty()) {
submitList(filled)
} else {
filled.forEachIndexed { i, scale ->
val cur = items.getOrNull(i)
if (cur == null || cur.address != scale.address || cur.weight != scale.weight || cur.state != scale.state) {
set(i, scale)
}
}
}
}
/**
* 将 ScaleData 列表按 SCALE_ORDER_22 重排后调用 update
*/
fun updateByAddress(scales: List<ScaleData>) {
val byAddress = scales.associateBy { it.address }
update(ScaleDeviceConfig.SCALE_ORDER_22.map { byAddress[it] })
}
/** 前4个位置为大格子(viewType=1),其余为小格子(viewType=0 */
override fun getItemViewType(position: Int, list: List<ScaleData>) = if (position < 4) 1 else 0
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val b = ListItemScale22RowBinding.inflate(LayoutInflater.from(context), parent, false)
val cellSize = if (viewType == 1) largeSize else smallSize
(b.root.layoutParams as? FlexboxLayoutManager.LayoutParams)?.apply {
width = cellSize
height = cellSize
setMargins(2.dp, 2.dp, 2.dp, 2.dp)
}
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvAddr.textSize = (baseSp * 0.16f).coerceIn(9f, 14f)
b.tvWeight.textSize = (baseSp * 0.22f).coerceIn(12f, 20f)
b.tvState.textSize = (baseSp * 0.14f).coerceIn(8f, 12f)
val vh = VH(b)
// 在 ViewHolder 创建时绑定点击,只执行一次,不受 notifyItemChanged 重绑定影响
b.root.setOnClickListener {
val pos = vh.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
items.getOrNull(pos)?.takeIf { it.address != 0 }?.let { onItemClick?.invoke(it) }
}
}
return vh
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: VH, position: Int, item: ScaleData?) {
val valid = (item?.address ?: 0) != 0
holder.b.tvAddr.text = if (valid) "${item!!.address}" else ""
holder.b.tvWeight.text = if (valid) "${item!!.weight}g" else ""
holder.b.tvState.text = if (valid) stateStr(item!!.state) else ""
// 高亮格子:红底白字;其余恢复默认
if (position == highlightedPosition) {
holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
holder.b.tvAddr.setTextColor(white)
holder.b.tvWeight.setTextColor(white)
holder.b.tvState.setTextColor(white)
} else {
holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
holder.b.tvAddr.setTextColor(normal)
holder.b.tvWeight.setTextColor(normal)
holder.b.tvState.setTextColor(normal)
}
}
/**
* 高亮指定位置的格子(红底白字),同时清除上一个高亮
* @param position 要高亮的格子索引
*/
fun highlightPosition(position: Int) {
val prev = highlightedPosition
highlightedPosition = position
if (prev >= 0) notifyItemChanged(prev)
if (position >= 0) notifyItemChanged(position)
}
/**
* 清除所有高亮,恢复默认样式
*/
fun clearHighlight() {
highlightPosition(-1)
}
private fun stateStr(state: Int) = when (state) {
WeightUtil.STATE_STABLE -> "稳定"
WeightUtil.STATE_UNSTABLE -> "不稳定"
WeightUtil.STATE_OVER_WEIGHT -> "超量"
else -> "$state"
}
}
@@ -1,80 +1,110 @@
package com.shuwei.dish.match.adapter package com.shuwei.dish.match.adapter
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.shuwei.dish.match.R import com.shuwei.dish.match.R
import com.shuwei.dish.match.databinding.ListItemSeasoningCellBinding import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
import com.shuwei.dish.match.entity.SeasoningEntity import com.shuwei.dish.match.scale.ScaleData
import com.shuwei.dish.match.scale.ScaleDeviceConfig import com.shuwei.dish.match.scale.ScaleDeviceConfig
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp import com.shuwei.dish.match.utils.ext.dp
/** /**
* 调料配置-下层(18格网格 Adapter * 18格网格 Adapter,同时服务于调料配置页和主设备秤总览页。
* 使用 GridLayoutManager6列)排列,第1行格子 margin 较大,第2-3行 margin 较小 *
* 实体类为 SeasoningEntity,格子显示调料名称 goodsName * @param showNameOnly true = 调料配置模式,仅显示 tvName,隐藏 tvWeight/tvState
* false = 秤总览模式,三行全部显示
*/ */
class Seasoning18GridAdapter : BaseQuickAdapter<SeasoningEntity, Seasoning18GridAdapter.VH>(mutableListOf()) { class Seasoning18GridAdapter(
private val showNameOnly: Boolean = false
) : BaseQuickAdapter<ScaleData, Seasoning18GridAdapter.VH>(mutableListOf()) {
/** 空位哨兵,sort=-1 表示无效 */ /** 空位哨兵,address=0 表示无效 */
private val empty = SeasoningEntity(goodsId = "").also { it.sort = -1 } private val empty = ScaleData("", 0, 0.0, -1, 0)
/** 当前高亮的格子位置,-1 表示无高亮 */ /** 当前高亮的格子位置,-1 表示无高亮 */
private var highlightedPosition: Int = -1 private var highlightedPosition: Int = -1
/** 点击回调,预留,暂不使用 */ /** 点击回调 */
var onItemClick: ((SeasoningEntity, Int) -> Unit)? = null var onItemClick: ((ScaleData, Int) -> Unit)? = null
inner class VH(val b: ListItemSeasoningCellBinding) : QuickViewHolder(b.root) inner class VH(val b: ListItemScale22RowBinding) : QuickViewHolder(b.root)
/** 前6个位置为第1行(viewType=0margin大),其余为第2-3行(viewType=1margin小) */ /** 前6个位置为第1行(viewType=0margin大),其余为第2-3行(viewType=1margin小) */
override fun getItemViewType(position: Int, list: List<SeasoningEntity>) = override fun getItemViewType(position: Int, list: List<ScaleData>) =
if (position < 6) 0 else 1 if (position < 6) 0 else 1
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val b = ListItemSeasoningCellBinding.inflate(LayoutInflater.from(context), parent, false) val b = ListItemScale22RowBinding.inflate(LayoutInflater.from(context), parent, false)
val margin = if (viewType == 0) 12.dp else 2.dp val margin = if (viewType == 0) 12.dp else 2.dp
val screenWidth = parent.resources.displayMetrics.widthPixels val screenWidth = parent.resources.displayMetrics.widthPixels
val cellSize = (screenWidth - 6 * margin * 2 - 10.dp) / 6 val cellSize = (screenWidth - 6 * margin * 2 - 10.dp) / 6
(b.root.layoutParams as? ViewGroup.MarginLayoutParams)?.also { (b.root.layoutParams as? ViewGroup.MarginLayoutParams)?.also {
it.width = cellSize it.width = cellSize
it.height = cellSize it.height = cellSize
// 第1行:顶部间距为0,底部间距2dp,左右保持原有 margin
if (viewType == 0) it.setMargins(margin, 0, margin, 2.dp) if (viewType == 0) it.setMargins(margin, 0, margin, 2.dp)
else it.setMargins(margin, margin, margin, margin) else it.setMargins(margin, margin, margin, margin)
} }
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt() val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvGoodsName.textSize = (baseSp * 0.18f).coerceIn(10f, 16f) b.tvName.textSize = (baseSp * 0.18f).coerceIn(10f, 16f)
b.tvWeight.textSize = (baseSp * 0.22f).coerceIn(12f, 20f)
b.tvState.textSize = (baseSp * 0.14f).coerceIn(8f, 12f)
// 调料配置模式隐藏重量和状态行
if (showNameOnly) {
b.tvWeight.visibility = View.GONE
b.tvState.visibility = View.GONE
}
val vh = VH(b) val vh = VH(b)
// 点击事件预留,暂不处理
b.root.setOnClickListener { b.root.setOnClickListener {
val pos = vh.bindingAdapterPosition val pos = vh.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) { if (pos != RecyclerView.NO_POSITION) {
items.getOrNull(pos)?.let { item -> onItemClick?.invoke(item, pos) } items.getOrNull(pos)?.takeIf { it.address != 0 }?.let { item -> onItemClick?.invoke(item, pos) }
} }
} }
return vh return vh
} }
override fun onBindViewHolder(holder: VH, position: Int, item: SeasoningEntity?) { @SuppressLint("SetTextI18n")
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-" override fun onBindViewHolder(holder: VH, position: Int, item: ScaleData?) {
val valid = (item?.address ?: 0) != 0
if (!valid) {
holder.b.tvName.text = if (showNameOnly) "-" else ""
holder.b.tvWeight.text = ""
holder.b.tvState.text = ""
} else {
holder.b.tvName.text = when {
!item!!.name.isNullOrBlank() -> item.name
showNameOnly -> "-"
else -> "${item.address}"
}
holder.b.tvWeight.text = "${item!!.weight}g"
holder.b.tvState.text = stateStr(item.state)
}
// 高亮格子:红底白字;其余恢复默认 // 高亮格子:红底白字;其余恢复默认
if (position == highlightedPosition) { if (position == highlightedPosition) {
holder.b.tvGoodsName.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444)) holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
holder.b.tvGoodsName.setTextColor(ContextCompat.getColor(holder.b.root.context, R.color.white)) val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
holder.b.tvName.setTextColor(white)
holder.b.tvWeight.setTextColor(white)
holder.b.tvState.setTextColor(white)
} else { } else {
holder.b.tvGoodsName.setBackgroundResource(R.drawable.shape_scale_cell) holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
holder.b.tvGoodsName.setTextColor(ContextCompat.getColor(holder.b.root.context, R.color.home_title)) val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
holder.b.tvName.setTextColor(normal)
holder.b.tvWeight.setTextColor(normal)
holder.b.tvState.setTextColor(normal)
} }
} }
/** /**
* 高亮指定位置的格子(红底白字),同时清除上一个高亮 * 高亮指定位置的格子(红底白字),同时清除上一个高亮
* @param position 要高亮的格子索引
*/ */
fun highlightPosition(position: Int) { fun highlightPosition(position: Int) {
val prev = highlightedPosition val prev = highlightedPosition
@@ -91,23 +121,46 @@ class Seasoning18GridAdapter : BaseQuickAdapter<SeasoningEntity, Seasoning18Grid
} }
/** /**
* 更新指定位置的调料名称并刷新对应格子 * 更新指定位置的名称并刷新对应格子
* @param position 格子索引
* @param name 新的调料名称
*/ */
fun updateItemName(position: Int, name: String) { fun updateItemName(position: Int, name: String) {
items.getOrNull(position)?.goodsName = name items.getOrNull(position)?.let {
notifyItemChanged(position) set(position, it.copy(name = name))
}
} }
/** /**
* 按 SCALE_ORDER_18 的 sort 顺序更新数据,空位用哨兵填充 * 按 SCALE_ORDER_18 的 sort 顺序更新数据,空位用哨兵填充
* 只更新显示字段有变化的格子,避免全量刷新导致 ViewHolder 重建影响点击监听
*/ */
fun update(seasoningList: List<SeasoningEntity>) { fun update(list: List<ScaleData>) {
val bySort = seasoningList.associateBy { it.sort } val byAddress = list.associateBy { it.address }
val filled = ScaleDeviceConfig.SCALE_ORDER_18.map { sort -> val filled = ScaleDeviceConfig.SCALE_ORDER_18.map { addr ->
bySort[sort] ?: empty.copy().also { it.sort = sort } byAddress[addr] ?: empty.copy(address = addr)
} }
submitList(filled) if (items.isEmpty()) {
submitList(filled)
} else {
filled.forEachIndexed { i, scale ->
val cur = items.getOrNull(i)
if (cur == null || cur.address != scale.address || cur.weight != scale.weight || cur.state != scale.state || cur.name != scale.name) {
set(i, scale)
}
}
}
}
/**
* 将 ScaleData 列表按 SCALE_ORDER_18 重排后调用 update
*/
fun updateByAddress(scales: List<ScaleData>) {
update(scales)
}
private fun stateStr(state: Int) = when (state) {
WeightUtil.STATE_STABLE -> "稳定"
WeightUtil.STATE_UNSTABLE -> "不稳定"
WeightUtil.STATE_OVER_WEIGHT -> "超量"
else -> ""
} }
} }
@@ -1,7 +1,9 @@
package com.shuwei.dish.match.adapter package com.shuwei.dish.match.adapter
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -9,41 +11,43 @@ import com.chad.library.adapter4.BaseQuickAdapter
import com.chad.library.adapter4.viewholder.QuickViewHolder import com.chad.library.adapter4.viewholder.QuickViewHolder
import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.R import com.shuwei.dish.match.R
import com.shuwei.dish.match.databinding.ListItemSeasoningCellBinding import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
import com.shuwei.dish.match.entity.SeasoningEntity import com.shuwei.dish.match.scale.ScaleData
import com.shuwei.dish.match.scale.ScaleDeviceConfig import com.shuwei.dish.match.scale.ScaleDeviceConfig
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp import com.shuwei.dish.match.utils.ext.dp
/** /**
* 调料配置-上层(22格网格 Adapter * 22格网格 Adapter,同时服务于调料配置页和主设备秤总览页。
* 使用 FlexboxLayoutManager 按列排列,前4个格子较大,其余较小
* 实体类为 SeasoningEntity,格子显示调料名称 goodsName
* *
* @param largeSize 前4个大格子的尺寸(px * @param largeSize 前4个大格子的尺寸(px
* @param smallSize 其余小格子的尺寸(px * @param smallSize 其余小格子的尺寸(px
* @param showNameOnly true = 调料配置模式,仅显示 tvName,隐藏 tvWeight/tvState
* false = 秤总览模式,三行全部显示
*/ */
class Seasoning22GridAdapter( class Seasoning22GridAdapter(
private val largeSize: Int, private val largeSize: Int,
private val smallSize: Int private val smallSize: Int,
) : BaseQuickAdapter<SeasoningEntity, Seasoning22GridAdapter.VH>(mutableListOf()) { private val showNameOnly: Boolean = false
) : BaseQuickAdapter<ScaleData, Seasoning22GridAdapter.VH>(mutableListOf()) {
/** 空位哨兵,sort=-1 表示无效 */ /** 空位哨兵,address=0 表示无效 */
private val empty = SeasoningEntity(goodsId = "").also { it.sort = -1 } private val empty = ScaleData("", 0, 0.0, -1, 0)
/** 当前高亮的格子位置,-1 表示无高亮 */ /** 当前高亮的格子位置,-1 表示无高亮 */
private var highlightedPosition: Int = -1 private var highlightedPosition: Int = -1
/** 点击回调,预留,暂不使用 */ /** 点击回调 */
var onItemClick: ((SeasoningEntity, Int) -> Unit)? = null var onItemClick: ((ScaleData, Int) -> Unit)? = null
inner class VH(val b: ListItemSeasoningCellBinding) : QuickViewHolder(b.root) inner class VH(val b: ListItemScale22RowBinding) : QuickViewHolder(b.root)
/** 前4个位置为大格子(viewType=1),其余为小格子(viewType=0 */ /** 前4个位置为大格子(viewType=1),其余为小格子(viewType=0 */
override fun getItemViewType(position: Int, list: List<SeasoningEntity>) = override fun getItemViewType(position: Int, list: List<ScaleData>) =
if (position < 4) 1 else 0 if (position < 4) 1 else 0
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH { override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
val b = ListItemSeasoningCellBinding.inflate(LayoutInflater.from(context), parent, false) val b = ListItemScale22RowBinding.inflate(LayoutInflater.from(context), parent, false)
val cellSize = if (viewType == 1) largeSize else smallSize val cellSize = if (viewType == 1) largeSize else smallSize
(b.root.layoutParams as? FlexboxLayoutManager.LayoutParams)?.apply { (b.root.layoutParams as? FlexboxLayoutManager.LayoutParams)?.apply {
width = cellSize width = cellSize
@@ -51,33 +55,59 @@ class Seasoning22GridAdapter(
setMargins(2.dp, 2.dp, 2.dp, 2.dp) setMargins(2.dp, 2.dp, 2.dp, 2.dp)
} }
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt() val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvGoodsName.textSize = (baseSp * 0.18f).coerceIn(10f, 16f) b.tvName.textSize = (baseSp * 0.18f).coerceIn(10f, 16f)
b.tvWeight.textSize = (baseSp * 0.22f).coerceIn(12f, 20f)
b.tvState.textSize = (baseSp * 0.14f).coerceIn(8f, 12f)
// 调料配置模式隐藏重量和状态行
if (showNameOnly) {
b.tvWeight.visibility = View.GONE
b.tvState.visibility = View.GONE
}
val vh = VH(b) val vh = VH(b)
// 点击事件预留,暂不处理
b.root.setOnClickListener { b.root.setOnClickListener {
val pos = vh.bindingAdapterPosition val pos = vh.bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) { if (pos != RecyclerView.NO_POSITION) {
items.getOrNull(pos)?.let { item -> onItemClick?.invoke(item, pos) } items.getOrNull(pos)?.takeIf { it.address != 0 }?.let { item -> onItemClick?.invoke(item, pos) }
} }
} }
return vh return vh
} }
override fun onBindViewHolder(holder: VH, position: Int, item: SeasoningEntity?) { @SuppressLint("SetTextI18n")
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-" override fun onBindViewHolder(holder: VH, position: Int, item: ScaleData?) {
val valid = (item?.address ?: 0) != 0
if (!valid) {
holder.b.tvName.text = if (showNameOnly) "-" else ""
holder.b.tvWeight.text = ""
holder.b.tvState.text = ""
} else {
// 有名称显示名称,无名称:调料配置显示"-",秤总览显示秤地址编号
holder.b.tvName.text = when {
!item!!.name.isNullOrBlank() -> item.name
showNameOnly -> "-"
else -> "${item.address}"
}
holder.b.tvWeight.text = "${item!!.weight}g"
holder.b.tvState.text = stateStr(item.state)
}
// 高亮格子:红底白字;其余恢复默认 // 高亮格子:红底白字;其余恢复默认
if (position == highlightedPosition) { if (position == highlightedPosition) {
holder.b.tvGoodsName.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444)) holder.b.root.setBackgroundColor(ContextCompat.getColor(holder.b.root.context, R.color.red_ff4444))
holder.b.tvGoodsName.setTextColor(ContextCompat.getColor(holder.b.root.context, R.color.white)) val white = ContextCompat.getColor(holder.b.root.context, R.color.white)
holder.b.tvName.setTextColor(white)
holder.b.tvWeight.setTextColor(white)
holder.b.tvState.setTextColor(white)
} else { } else {
holder.b.tvGoodsName.setBackgroundResource(R.drawable.shape_scale_cell) holder.b.root.setBackgroundResource(R.drawable.shape_scale_cell)
holder.b.tvGoodsName.setTextColor(ContextCompat.getColor(holder.b.root.context, R.color.home_title)) val normal = ContextCompat.getColor(holder.b.root.context, R.color.home_title)
holder.b.tvName.setTextColor(normal)
holder.b.tvWeight.setTextColor(normal)
holder.b.tvState.setTextColor(normal)
} }
} }
/** /**
* 高亮指定位置的格子(红底白字),同时清除上一个高亮 * 高亮指定位置的格子(红底白字),同时清除上一个高亮
* @param position 要高亮的格子索引
*/ */
fun highlightPosition(position: Int) { fun highlightPosition(position: Int) {
val prev = highlightedPosition val prev = highlightedPosition
@@ -94,23 +124,46 @@ class Seasoning22GridAdapter(
} }
/** /**
* 更新指定位置的调料名称并刷新对应格子 * 更新指定位置的名称并刷新对应格子
* @param position 格子索引
* @param name 新的调料名称
*/ */
fun updateItemName(position: Int, name: String) { fun updateItemName(position: Int, name: String) {
items.getOrNull(position)?.goodsName = name items.getOrNull(position)?.let {
notifyItemChanged(position) set(position, it.copy(name = name))
}
} }
/** /**
* 按 SCALE_ORDER_22 的 sort 顺序更新数据,空位用哨兵填充 * 按 SCALE_ORDER_22 的 sort 顺序更新数据,空位用哨兵填充
* 只更新显示字段有变化的格子,避免全量刷新导致 ViewHolder 重建影响点击监听
*/ */
fun update(seasoningList: List<SeasoningEntity>) { fun update(list: List<ScaleData>) {
val bySort = seasoningList.associateBy { it.sort } val byAddress = list.associateBy { it.address }
val filled = ScaleDeviceConfig.SCALE_ORDER_22.map { sort -> val filled = ScaleDeviceConfig.SCALE_ORDER_22.map { addr ->
bySort[sort] ?: empty.copy().also { it.sort = sort } byAddress[addr] ?: empty.copy(address = addr)
} }
submitList(filled) if (items.isEmpty()) {
submitList(filled)
} else {
filled.forEachIndexed { i, scale ->
val cur = items.getOrNull(i)
if (cur == null || cur.address != scale.address || cur.weight != scale.weight || cur.state != scale.state || cur.name != scale.name) {
set(i, scale)
}
}
}
}
/**
* 将 ScaleData 列表按 SCALE_ORDER_22 重排后调用 update
*/
fun updateByAddress(scales: List<ScaleData>) {
update(scales)
}
private fun stateStr(state: Int) = when (state) {
WeightUtil.STATE_STABLE -> "稳定"
WeightUtil.STATE_UNSTABLE -> "不稳定"
WeightUtil.STATE_OVER_WEIGHT -> "超量"
else -> ""
} }
} }
@@ -15,5 +15,6 @@ data class ScaleData(
val weight: Double, val weight: Double,
val state: Int, val state: Int,
val ts: Long, val ts: Long,
val ip: String = "" val ip: String = "",
val name: String? = null
) )
@@ -18,8 +18,8 @@ import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.R import com.shuwei.dish.match.R
import com.shuwei.dish.match.adapter.Scale18GridAdapter import com.shuwei.dish.match.adapter.Seasoning18GridAdapter
import com.shuwei.dish.match.adapter.Scale22GridAdapter import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
import com.shuwei.dish.match.base.BaseActivity import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.dialog.CommonDialog import com.shuwei.dish.match.dialog.CommonDialog
import com.shuwei.dish.match.databinding.ActivityMasterScaleBinding import com.shuwei.dish.match.databinding.ActivityMasterScaleBinding
@@ -249,7 +249,7 @@ class MasterScaleActivity : BaseActivity() {
// ── ViewHolder: 22个秤 ───────────────────────────────────────────────── // ── ViewHolder: 22个秤 ─────────────────────────────────────────────────
private inner class Scale22VH(val b: ListTypeScale22Binding) : RecyclerView.ViewHolder(b.root) { private inner class Scale22VH(val b: ListTypeScale22Binding) : RecyclerView.ViewHolder(b.root) {
private var innerAdapter: Scale22GridAdapter? = null private var innerAdapter: Seasoning22GridAdapter? = null
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun bind(group: DeviceGroup) { fun bind(group: DeviceGroup) {
@@ -269,8 +269,8 @@ class MasterScaleActivity : BaseActivity() {
alignItems = AlignItems.FLEX_START alignItems = AlignItems.FLEX_START
} }
b.rvScales.itemAnimator = null b.rvScales.itemAnimator = null
innerAdapter = Scale22GridAdapter(largeSize, smallSize).apply { innerAdapter = Seasoning22GridAdapter(largeSize, smallSize, showNameOnly = false).apply {
onItemClick = { scale -> onItemClick = { scale, _ ->
showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address) showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address)
} }
} }
@@ -288,7 +288,7 @@ class MasterScaleActivity : BaseActivity() {
// ── ViewHolder: 18个秤 ───────────────────────────────────────────────── // ── ViewHolder: 18个秤 ─────────────────────────────────────────────────
private inner class Scale18VH(val b: ListTypeScale18Binding) : RecyclerView.ViewHolder(b.root) { private inner class Scale18VH(val b: ListTypeScale18Binding) : RecyclerView.ViewHolder(b.root) {
private var innerAdapter: Scale18GridAdapter? = null private var innerAdapter: Seasoning18GridAdapter? = null
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun bind(group: DeviceGroup) { fun bind(group: DeviceGroup) {
@@ -303,8 +303,8 @@ class MasterScaleActivity : BaseActivity() {
} }
b.rvScales.layoutManager = gridLayoutManager b.rvScales.layoutManager = gridLayoutManager
b.rvScales.itemAnimator = null b.rvScales.itemAnimator = null
innerAdapter = Scale18GridAdapter().apply { innerAdapter = Seasoning18GridAdapter(showNameOnly = false).apply {
onItemClick = { scale -> onItemClick = { scale, _ ->
showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address) showTareDialog(deviceId = scale.deviceId, ip = scale.ip, address = scale.address)
} }
} }
@@ -1,142 +0,0 @@
package com.shuwei.dish.match.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.AlignItems
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.databinding.ActivityScale22GridBinding
import com.shuwei.dish.match.databinding.ListItemScale22RowBinding
import com.shuwei.dish.match.scale.ScaleData
import com.shuwei.dish.match.scale.ScaleServiceManager
import com.shuwei.dish.match.utils.WeightUtil
import com.shuwei.dish.match.utils.ext.dp
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
/** 22格设备的 deviceId */
private const val DEVICE_ID_22 = "a46fa55c-113c-3511-bb1f-41e5eff77c4b"
/**
* 列优先顺序:大列1(20,22) → 大列2(19,21) → 小列1~6
* FlexboxLayoutManager COLUMN 方向按列填充,顺序天然对应
*/
private val SCALE_ORDER_22 = listOf(20, 22, 19, 21, 6, 12, 18, 5, 11, 17, 4, 10, 16, 3, 9, 15, 2, 8, 14, 1, 7, 13)
/** 前4个 item(大列1+大列2,各2行)为大格子 */
private fun isLargeCell(position: Int) = position < 4
/**
* 22格秤混合网格布局页
* FlexboxLayoutManager(COLUMN) 竖向排列:
* - 大格子 flexBasisPercent=1.5/9,每列2个,自动换列
* - 小格子 flexBasisPercent=1.0/9,每列3个,自动换列
*/
class Scale22GridActivity : BaseActivity() {
private lateinit var binding: ActivityScale22GridBinding
private val scaleList = mutableListOf<ScaleData?>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityScale22GridBinding.inflate(layoutInflater)
setContentView(binding.root)
setHeaderBackground()
binding.ivBack.setOnClickListener { finish() }
// 格子尺寸计算:
// 屏幕宽 - 8列×左右margin(2dp×2) = 可用宽,共9份(大1.5+小1.0×6)
val screenWidth = resources.displayMetrics.widthPixels
val usable = screenWidth - 8 * 4.dp - 4.dp // 减去8列格子margin + RecyclerView左右margin各2dp
val smallSize = usable / 9
val largeSize = (usable - smallSize * 6) / 2 // 剩余宽度平分给2列大格子
// 高度以小格子3行为准(3行×格子高 + 3行×上下margin各2dp
val rvHeight = smallSize * 3 + 3 * 4.dp
binding.rvScale22.layoutParams = binding.rvScale22.layoutParams.also {
it.height = rvHeight
}
binding.rvScale22.layoutManager = FlexboxLayoutManager(this).apply {
flexDirection = FlexDirection.COLUMN
flexWrap = FlexWrap.WRAP
alignItems = AlignItems.FLEX_START
}
binding.rvScale22.itemAnimator = null
binding.rvScale22.adapter = Scale22Adapter(scaleList, largeSize, smallSize)
observeScaleData()
}
private fun observeScaleData() {
val flow = ScaleServiceManager.allScales ?: return
lifecycleScope.launch {
flow.collectLatest { scaleMap ->
val scaleByAddress = scaleMap.values
.filter { it.deviceId == DEVICE_ID_22 }
.associateBy { it.address }
val newList = SCALE_ORDER_22.map { scaleByAddress[it] }
if (scaleList.isEmpty()) {
scaleList.addAll(newList)
binding.rvScale22.adapter?.notifyItemRangeInserted(0, scaleList.size)
} else {
newList.forEachIndexed { i, scale ->
if (scaleList[i] != scale) {
scaleList[i] = scale
binding.rvScale22.adapter?.notifyItemChanged(i)
}
}
}
}
}
}
private inner class Scale22Adapter(
private val data: List<ScaleData?>,
private val largeSize: Int, // 大格子宽高(px
private val smallSize: Int // 小格子宽高(px
) : RecyclerView.Adapter<Scale22Adapter.VH>() {
inner class VH(val b: ListItemScale22RowBinding) : RecyclerView.ViewHolder(b.root)
override fun getItemViewType(position: Int) = if (isLargeCell(position)) 1 else 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val b = ListItemScale22RowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val cellSize = if (viewType == 1) largeSize else smallSize
// 固定宽高实现正方形,FlexboxLayoutManager COLUMN 方向按高度装满后自动换列
(b.root.layoutParams as? FlexboxLayoutManager.LayoutParams)?.apply {
width = cellSize
height = cellSize
setMargins(2.dp, 2.dp, 2.dp, 2.dp)
}
val baseSp = (cellSize / parent.resources.displayMetrics.density).toInt()
b.tvAddr.textSize = (baseSp * 0.16f).coerceIn(9f, 14f)
b.tvWeight.textSize = (baseSp * 0.22f).coerceIn(12f, 20f)
b.tvState.textSize = (baseSp * 0.14f).coerceIn(8f, 12f)
return VH(b)
}
override fun getItemCount() = data.size
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: VH, position: Int) {
val scale = data[position]
holder.b.tvAddr.text = scale?.let { "${it.address}" } ?: ""
holder.b.tvWeight.text = scale?.let { "${it.weight}g" } ?: ""
holder.b.tvState.text = when (scale?.state) {
WeightUtil.STATE_STABLE -> "稳定"
WeightUtil.STATE_UNSTABLE -> "不稳定"
WeightUtil.STATE_OVER_WEIGHT -> "超量"
null -> ""
else -> "${scale.state}"
}
}
}
}
@@ -13,8 +13,8 @@ import com.google.android.flexbox.AlignItems
import com.google.android.flexbox.FlexDirection import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.FlexboxLayoutManager
import com.shuwei.dish.match.adapter.Scale18GridAdapter import com.shuwei.dish.match.adapter.Seasoning18GridAdapter
import com.shuwei.dish.match.adapter.Scale22GridAdapter import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
import com.shuwei.dish.match.adapter.ScaleRowAdapter import com.shuwei.dish.match.adapter.ScaleRowAdapter
import com.shuwei.dish.match.base.BaseActivity import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.base.GlobalData import com.shuwei.dish.match.base.GlobalData
@@ -40,9 +40,9 @@ class SlaveActivity : BaseActivity() {
private val linearAdapter = ScaleRowAdapter() private val linearAdapter = ScaleRowAdapter()
/** 22个秤网格 adapter */ /** 22个秤网格 adapter */
private var scale22Adapter: Scale22GridAdapter? = null private var scale22Adapter: Seasoning22GridAdapter? = null
/** 18个秤网格 adapter */ /** 18个秤网格 adapter */
private var scale18Adapter: Scale18GridAdapter? = null private var scale18Adapter: Seasoning18GridAdapter? = null
/** 已连接的主设备数量(有连接即代表主设备在线) */ /** 已连接的主设备数量(有连接即代表主设备在线) */
private var masterConnected = false private var masterConnected = false
@@ -95,8 +95,8 @@ class SlaveActivity : BaseActivity() {
flexWrap = FlexWrap.WRAP flexWrap = FlexWrap.WRAP
alignItems = AlignItems.FLEX_START alignItems = AlignItems.FLEX_START
} }
scale22Adapter = Scale22GridAdapter(largeSize, smallSize).also { scale22Adapter = Seasoning22GridAdapter(largeSize, smallSize, showNameOnly = false).also {
it.onItemClick = { scale -> showTareDialog(scale.address) } it.onItemClick = { scale, _ -> showTareDialog(scale.address) }
} }
binding.rvScaleList.adapter = scale22Adapter binding.rvScaleList.adapter = scale22Adapter
} }
@@ -107,8 +107,8 @@ class SlaveActivity : BaseActivity() {
override fun getSpanSize(position: Int) = 1 override fun getSpanSize(position: Int) = 1
} }
} }
scale18Adapter = Scale18GridAdapter().also { scale18Adapter = Seasoning18GridAdapter(showNameOnly = false).also {
it.onItemClick = { scale -> showTareDialog(scale.address) } it.onItemClick = { scale, _ -> showTareDialog(scale.address) }
} }
binding.rvScaleList.adapter = scale18Adapter binding.rvScaleList.adapter = scale18Adapter
} }
@@ -45,7 +45,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
// private lateinit var appViewModel: AppViewModel // private lateinit var appViewModel: AppViewModel
private val adapter22 by lazy { buildAdapter22() } private val adapter22 by lazy { buildAdapter22() }
private val adapter18 by lazy { Seasoning18GridAdapter() } private val adapter18 by lazy { Seasoning18GridAdapter(showNameOnly = true) }
/** 各秤的上一次重量快照,key 格式 "{deviceId}#{address}",用于计算 delta */ /** 各秤的上一次重量快照,key 格式 "{deviceId}#{address}",用于计算 delta */
private val weightSnapshot = mutableMapOf<String, Double>() private val weightSnapshot = mutableMapOf<String, Double>()
@@ -96,7 +96,7 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
val usable = resources.displayMetrics.widthPixels - 8 * 4.dp - 10.dp val usable = resources.displayMetrics.widthPixels - 8 * 4.dp - 10.dp
val smallSize = usable / 9 val smallSize = usable / 9
val largeSize = (usable - smallSize * 6) / 2 val largeSize = (usable - smallSize * 6) / 2
return Seasoning22GridAdapter(largeSize, smallSize) return Seasoning22GridAdapter(largeSize, smallSize, showNameOnly = true)
} }
/** 配置两个 RecyclerView */ /** 配置两个 RecyclerView */
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@color/bg_color">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="22格秤数据"
android:textColor="@color/home_title"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/ivBack"
android:layout_width="70dp"
android:layout_height="60dp"
android:paddingStart="30dp"
android:paddingEnd="10dp"
android:src="@drawable/ic_back"
app:layout_constraintBottom_toBottomOf="@id/tvTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/tvTitle"
tools:ignore="ContentDescription" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvScale22"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:overScrollMode="never"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle"
tools:listitem="@layout/list_item_scale22_row" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -9,7 +9,7 @@
android:background="@drawable/shape_scale_cell"> android:background="@drawable/shape_scale_cell">
<TextView <TextView
android:id="@+id/tvAddr" android:id="@+id/tvName"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"