feat(activity): 弹窗食材/调料查询使用独立 StateFlow,新增调料列表双布局切换功能
- NetViewModel 新增 foodSearchGoodsListState 和 queryFoodSearchGoodsList,与 goodsListState 隔离 - FoodSearchDialog、SeasoningSelectDialog 改用弹窗专用 State,避免影响 FoodRecognizeActivity 列表 - SeasoningWeightAdapter 支持 Grid(4列)/List(2列)双布局模式 - SubmitFoodActivity 添加调料列表布局切换按钮 - FoodModule 变量重命名并添加未初始化保护 - 注释掉 mock 食材数据,调整相关布局边距与文字截断 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,14 +6,25 @@ import android.view.ViewGroup
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.shuwei.dish.match.databinding.ItemSeasoningWeightBinding
|
||||
import com.shuwei.dish.match.databinding.ItemSeasoningWeightListBinding
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
|
||||
/**
|
||||
* 调料使用重量列表 Adapter
|
||||
* 用于 SubmitFoodActivity 展示各调料槽位的实时用量
|
||||
* 同名调料已在外部聚合,adapter 按 goodsName 作为唯一标识
|
||||
* 支持两种布局模式:
|
||||
* - VIEW_TYPE_GRID(默认):4 列卡片,名称与重量垂直排列
|
||||
* - VIEW_TYPE_LIST:2 列,名称与重量水平排列,名称占剩余空间
|
||||
*/
|
||||
class SeasoningWeightAdapter : BaseQuickAdapter<SeasoningWeightAdapter.Item, SeasoningWeightAdapter.VH>() {
|
||||
class SeasoningWeightAdapter : BaseQuickAdapter<SeasoningWeightAdapter.Item, QuickViewHolder>() {
|
||||
|
||||
companion object {
|
||||
/** 4 列卡片模式 */
|
||||
const val VIEW_TYPE_GRID = 0
|
||||
/** 2 列水平模式 */
|
||||
const val VIEW_TYPE_LIST = 1
|
||||
}
|
||||
|
||||
/** 调料展示数据项,key = goodsName(同名调料已聚合) */
|
||||
data class Item(
|
||||
@@ -23,6 +34,13 @@ class SeasoningWeightAdapter : BaseQuickAdapter<SeasoningWeightAdapter.Item, Sea
|
||||
val useWeight: Double
|
||||
)
|
||||
|
||||
/** 当前布局模式,由外部切换后调用 notifyDataSetChanged 生效 */
|
||||
var isListMode: Boolean = false
|
||||
|
||||
override fun getItemViewType(position: Int, list: List<Item>): Int {
|
||||
return if (isListMode) VIEW_TYPE_LIST else VIEW_TYPE_GRID
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单个 item,按 goodsName 匹配;不存在则追加
|
||||
*/
|
||||
@@ -43,18 +61,21 @@ class SeasoningWeightAdapter : BaseQuickAdapter<SeasoningWeightAdapter.Item, Sea
|
||||
if (idx >= 0) removeAt(idx)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
||||
val binding = ItemSeasoningWeightBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
return VH(binding)
|
||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): QuickViewHolder {
|
||||
return if (viewType == VIEW_TYPE_LIST) {
|
||||
val binding = ItemSeasoningWeightListBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
QuickViewHolder(binding.root)
|
||||
} else {
|
||||
val binding = ItemSeasoningWeightBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
QuickViewHolder(binding.root)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: VH, position: Int, item: Item?) {
|
||||
override fun onBindViewHolder(holder: QuickViewHolder, position: Int, item: Item?) {
|
||||
item ?: return
|
||||
holder.binding.tvSeasoningName.text = item.goodsName
|
||||
val showWeight = "${item.useWeight.roundedDecimalPlace(1)}g"
|
||||
holder.binding.tvSeasoningWeight.text = showWeight
|
||||
holder.setText(com.shuwei.dish.match.R.id.tvSeasoningName, item.goodsName)
|
||||
holder.setText(com.shuwei.dish.match.R.id.tvSeasoningWeight, showWeight)
|
||||
}
|
||||
|
||||
inner class VH(var binding: ItemSeasoningWeightBinding) : QuickViewHolder(binding.root)
|
||||
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class FoodSearchDialog(
|
||||
}
|
||||
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(false)
|
||||
setEnableRefresh(true)
|
||||
setEnableLoadMore(false)
|
||||
setOnRefreshListener { pageNo = 1; getGoodsList() }
|
||||
setOnLoadMoreListener { getGoodsList() }
|
||||
@@ -175,12 +175,13 @@ class FoodSearchDialog(
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集 goodsListState,统一处理 Loading / Success / Error 状态
|
||||
* 收集 foodSearchGoodsListState,统一处理 Loading / Success / Error 状态
|
||||
* 使用独立的 State,避免与 FoodRecognizeActivity 等页面共用 goodsListState 产生干扰
|
||||
*/
|
||||
private fun initObserver() {
|
||||
activity.lifecycleScope.launch {
|
||||
activity.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
activity.netViewModel.goodsListState.collect { state ->
|
||||
activity.netViewModel.foodSearchGoodsListState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Success -> loadGoodsList(state.data)
|
||||
is UiState.Error -> {
|
||||
@@ -208,10 +209,10 @@ class FoodSearchDialog(
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求食材列表
|
||||
* 请求食材列表,使用弹窗专用接口,结果写入 foodSearchGoodsListState
|
||||
*/
|
||||
private fun getGoodsList() {
|
||||
activity.netViewModel.queryGoodsList(
|
||||
activity.netViewModel.queryFoodSearchGoodsList(
|
||||
goodsType = "0",
|
||||
pageNum = pageNo,
|
||||
pageSize = PAGE_SIZE,
|
||||
|
||||
@@ -102,7 +102,7 @@ class SeasoningSelectDialog(
|
||||
}
|
||||
|
||||
binding.refreshLayout.run {
|
||||
setEnableRefresh(false)
|
||||
setEnableRefresh(true)
|
||||
setEnableLoadMore(false)
|
||||
setOnRefreshListener { pageNo = 1; getGoodsList() }
|
||||
setOnLoadMoreListener { getGoodsList() }
|
||||
@@ -117,7 +117,7 @@ class SeasoningSelectDialog(
|
||||
super.show()
|
||||
// 启动 StateFlow 收集,弹窗关闭时由 setOnDismissListener 取消
|
||||
collectJob = activity.lifecycleScope.launch {
|
||||
activity.netViewModel.goodsListState.collect { state ->
|
||||
activity.netViewModel.foodSearchGoodsListState.collect { state ->
|
||||
when (state) {
|
||||
is UiState.Loading -> {}
|
||||
is UiState.Success -> loadGoodsList(state.data)
|
||||
@@ -186,7 +186,7 @@ class SeasoningSelectDialog(
|
||||
* 请求调料列表
|
||||
*/
|
||||
private fun getGoodsList() {
|
||||
activity.netViewModel.queryGoodsList(
|
||||
activity.netViewModel.queryFoodSearchGoodsList(
|
||||
goodsType = "1",
|
||||
pageNum = pageNo,
|
||||
pageSize = PAGE_SIZE,
|
||||
|
||||
@@ -102,6 +102,12 @@ class NetViewModel(
|
||||
private val _goodsListState = MutableStateFlow<UiState<MutableList<GoodsItem>?>>(UiState.Idle)
|
||||
val goodsListState: StateFlow<UiState<MutableList<GoodsItem>?>> = _goodsListState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 食材搜索弹窗专用的 UI 状态流,与 goodsListState 隔离,避免弹窗请求影响其他页面
|
||||
*/
|
||||
private val _foodSearchGoodsListState = MutableStateFlow<UiState<MutableList<GoodsItem>?>>(UiState.Idle)
|
||||
val foodSearchGoodsListState: StateFlow<UiState<MutableList<GoodsItem>?>> = _foodSearchGoodsListState.asStateFlow()
|
||||
|
||||
/**
|
||||
* 查询物品信息列表(食材 goodsType=0,调料 goodsType=1 共用)
|
||||
* @param goodsType 物品类型:0=食材,1=调料
|
||||
@@ -133,6 +139,37 @@ class NetViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 食材搜索弹窗专用的查询方法,结果写入 foodSearchGoodsListState,不影响 goodsListState
|
||||
* @param goodsType 物品类型:0=食材,1=调料
|
||||
* @param placeId 场所 ID,默认取当前食堂 ID
|
||||
* @param pageNum 页码,默认第 1 页
|
||||
* @param pageSize 每页条数,默认 50
|
||||
* @param goodsName 按名称模糊搜索,为 null 时不传该字段
|
||||
* @param goodsNames 按名称+净材种类列表批量查询,为 null 时不传该字段
|
||||
*/
|
||||
fun queryFoodSearchGoodsList(
|
||||
goodsType: String,
|
||||
placeId: String = BaseApp.canteenId,
|
||||
pageNum: Int = 1,
|
||||
pageSize: Int = 50,
|
||||
goodsName: String? = null,
|
||||
goodsNames: List<GoodsNameQueryDTO>? = null
|
||||
) {
|
||||
val param = mutableMapOf<String, Any>(
|
||||
"goodsType" to goodsType,
|
||||
"placeId" to placeId,
|
||||
"pageNum" to pageNum,
|
||||
"pageSize" to pageSize
|
||||
)
|
||||
goodsName?.let { param["goodsName"] = it }
|
||||
goodsNames?.let { param["goodsNames"] = it }
|
||||
viewModelScope.launch {
|
||||
_foodSearchGoodsListState.value = UiState.Loading
|
||||
_foodSearchGoodsListState.value = repository.queryGoodsList(param)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传采集菜品信息 UI 状态流,UI 层通过 collect 监听
|
||||
*/
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.io.InputStream
|
||||
|
||||
object FoodModule {
|
||||
|
||||
private lateinit var module_mobile: Module
|
||||
private lateinit var module: Module
|
||||
|
||||
private val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f)
|
||||
private val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f)
|
||||
@@ -37,8 +37,8 @@ object FoodModule {
|
||||
|
||||
suspend fun init(context: Context) {
|
||||
withContext(Dispatchers.IO) {
|
||||
module_mobile = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt"))
|
||||
initDefFoodData(context)
|
||||
module = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt"))
|
||||
// initDefFoodData(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,11 @@ object FoodModule {
|
||||
// }
|
||||
|
||||
fun bitmap2FloatArray(originBitmap: Bitmap, isRecycle: Boolean): FloatArray? {
|
||||
// 模型未初始化时直接返回 null,避免 UninitializedPropertyAccessException
|
||||
if (!::module.isInitialized) {
|
||||
logInfo("bitmap2FloatArray: module 尚未初始化,跳过推理")
|
||||
return null
|
||||
}
|
||||
var rgb565Bitmap: Bitmap? = null
|
||||
try {
|
||||
val scaledBitmap = originBitmap.scale(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT)
|
||||
@@ -64,7 +69,7 @@ object FoodModule {
|
||||
NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB
|
||||
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
|
||||
)
|
||||
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
|
||||
val outputTensor = module.forward(IValue.from(inputTensor)).toTensor()
|
||||
return outputTensor.dataAsFloatArray
|
||||
} catch (e: OutOfMemoryError) {
|
||||
e.printStackTrace()
|
||||
|
||||
@@ -156,7 +156,7 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 RecyclerView,24列 GridLayoutManager */
|
||||
/** 初始化 RecyclerView,默认 4 列 GridLayoutManager */
|
||||
private fun setupRecyclerView() {
|
||||
binding.rvSeasoning.let {
|
||||
it.itemAnimator = null
|
||||
@@ -303,6 +303,13 @@ class SubmitFoodActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun addViewListener() {
|
||||
// 切换调料列表布局:4 列卡片 ↔ 2 列水平
|
||||
binding.ivSeasoningLayoutToggle.setOnClickListener {
|
||||
seasoningAdapter.isListMode = !seasoningAdapter.isListMode
|
||||
val spanCount = if (seasoningAdapter.isListMode) 2 else 4
|
||||
(binding.rvSeasoning.layoutManager as? GridLayoutManager)?.spanCount = spanCount
|
||||
seasoningAdapter.notifyDataSetChanged()
|
||||
}
|
||||
binding.btnCook.clickWithDebounce {
|
||||
val content = getRemindSpannable("开始制作")
|
||||
showRemindDialog(content) { cook() }
|
||||
|
||||
@@ -18,27 +18,27 @@ import com.shuwei.dish.match.utils.ext.toast
|
||||
* TODO: 联调完成后删除
|
||||
*/
|
||||
fun buildMockGoodsList(): List<GoodsItem> = mutableListOf(
|
||||
GoodsItem(goodsId = "1", goodsName = "土豆", rawMaterialsType = "土豆丝,土豆条,土豆片,土豆丁"),
|
||||
GoodsItem(goodsId = "2", goodsName = "胡萝卜", rawMaterialsType = "胡萝卜丝,胡萝卜片,胡萝卜丁"),
|
||||
GoodsItem(goodsId = "3", goodsName = "黄瓜", rawMaterialsType = "黄瓜丝,黄瓜片,黄瓜丁,黄瓜块"),
|
||||
GoodsItem(goodsId = "4", goodsName = "洋葱", rawMaterialsType = "洋葱丝,洋葱丁,洋葱圈"),
|
||||
GoodsItem(goodsId = "5", goodsName = "白菜", rawMaterialsType = "白菜丝,白菜块,白菜叶"),
|
||||
GoodsItem(goodsId = "6", goodsName = "豆腐", rawMaterialsType = "豆腐块,豆腐丁"),
|
||||
GoodsItem(goodsId = "7", goodsName = "猪肉", rawMaterialsType = "猪肉丝,猪肉片,猪肉丁,猪肉块"),
|
||||
GoodsItem(goodsId = "8", goodsName = "鸡胸肉", rawMaterialsType = "鸡胸肉丝,鸡胸肉片,鸡胸肉丁"),
|
||||
GoodsItem(goodsId = "9", goodsName = "牛肉", rawMaterialsType = "牛肉丝,牛肉片,牛肉块"),
|
||||
GoodsItem(goodsId = "10", goodsName = "虾仁", rawMaterialsType = "整虾仁,切段虾仁"),
|
||||
GoodsItem(goodsId = "11", goodsName = "茄子", rawMaterialsType = "茄子丝,茄子片,茄子块,茄子条"),
|
||||
GoodsItem(goodsId = "12", goodsName = "青椒", rawMaterialsType = "青椒丝,青椒片,青椒块"),
|
||||
GoodsItem(goodsId = "13", goodsName = "西红柿", rawMaterialsType = "西红柿片,西红柿块,西红柿丁"),
|
||||
GoodsItem(goodsId = "14", goodsName = "芹菜", rawMaterialsType = "芹菜段,芹菜丝"),
|
||||
GoodsItem(goodsId = "15", goodsName = "莲藕", rawMaterialsType = "莲藕片,莲藕丁,莲藕丝"),
|
||||
// 以下5条 rawMaterialsType 为空,测试无净材数据场景
|
||||
GoodsItem(goodsId = "16", goodsName = "菠菜"),
|
||||
GoodsItem(goodsId = "17", goodsName = "生菜"),
|
||||
GoodsItem(goodsId = "18", goodsName = "香菇"),
|
||||
GoodsItem(goodsId = "19", goodsName = "木耳"),
|
||||
GoodsItem(goodsId = "20", goodsName = "豆芽"),
|
||||
// GoodsItem(goodsId = "1", goodsName = "土豆", rawMaterialsType = "土豆丝,土豆条,土豆片,土豆丁"),
|
||||
// GoodsItem(goodsId = "2", goodsName = "胡萝卜", rawMaterialsType = "胡萝卜丝,胡萝卜片,胡萝卜丁"),
|
||||
// GoodsItem(goodsId = "3", goodsName = "黄瓜", rawMaterialsType = "黄瓜丝,黄瓜片,黄瓜丁,黄瓜块"),
|
||||
// GoodsItem(goodsId = "4", goodsName = "洋葱", rawMaterialsType = "洋葱丝,洋葱丁,洋葱圈"),
|
||||
// GoodsItem(goodsId = "5", goodsName = "白菜", rawMaterialsType = "白菜丝,白菜块,白菜叶"),
|
||||
// GoodsItem(goodsId = "6", goodsName = "豆腐", rawMaterialsType = "豆腐块,豆腐丁"),
|
||||
// GoodsItem(goodsId = "7", goodsName = "猪肉", rawMaterialsType = "猪肉丝,猪肉片,猪肉丁,猪肉块"),
|
||||
// GoodsItem(goodsId = "8", goodsName = "鸡胸肉", rawMaterialsType = "鸡胸肉丝,鸡胸肉片,鸡胸肉丁"),
|
||||
// GoodsItem(goodsId = "9", goodsName = "牛肉", rawMaterialsType = "牛肉丝,牛肉片,牛肉块"),
|
||||
// GoodsItem(goodsId = "10", goodsName = "虾仁", rawMaterialsType = "整虾仁,切段虾仁"),
|
||||
// GoodsItem(goodsId = "11", goodsName = "茄子", rawMaterialsType = "茄子丝,茄子片,茄子块,茄子条"),
|
||||
// GoodsItem(goodsId = "12", goodsName = "青椒", rawMaterialsType = "青椒丝,青椒片,青椒块"),
|
||||
// GoodsItem(goodsId = "13", goodsName = "西红柿", rawMaterialsType = "西红柿片,西红柿块,西红柿丁"),
|
||||
// GoodsItem(goodsId = "14", goodsName = "芹菜", rawMaterialsType = "芹菜段,芹菜丝"),
|
||||
// GoodsItem(goodsId = "15", goodsName = "莲藕", rawMaterialsType = "莲藕片,莲藕丁,莲藕丝"),
|
||||
// // 以下5条 rawMaterialsType 为空,测试无净材数据场景
|
||||
// GoodsItem(goodsId = "16", goodsName = "菠菜"),
|
||||
// GoodsItem(goodsId = "17", goodsName = "生菜"),
|
||||
// GoodsItem(goodsId = "18", goodsName = "香菇"),
|
||||
// GoodsItem(goodsId = "19", goodsName = "木耳"),
|
||||
// GoodsItem(goodsId = "20", goodsName = "豆芽"),
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
@@ -16,22 +16,39 @@
|
||||
android:background="@drawable/shape_white_30_corners"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginStart="22dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:text="@string/seasoning"
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="28sp" />
|
||||
android:layout_marginEnd="22dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/seasoning"
|
||||
android:textColor="@color/black666"
|
||||
android:textSize="28sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivSeasoningLayoutToggle"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:contentDescription="切换布局"
|
||||
android:src="@drawable/ic_switch_box"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvSeasoning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="660dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
tools:itemCount="26"
|
||||
|
||||
@@ -69,8 +69,6 @@
|
||||
android:layout_width="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
|
||||
@@ -81,6 +79,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:nestedScrollingEnabled="true"
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@drawable/shape_white_fb_15_corners2">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSeasoningName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="土豆丝" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSeasoningWeight"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textColor="@color/dish_green"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="100g" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -26,6 +26,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@color/black"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user