feat(form): 实现餐品净菜包装表单功能
- 新增 CHILDREN 字段类型支持动态子列表 - 实现包含食材的嵌套表单结构 - 添加餐品包装相关字段配置 - 集成下拉选项和日期选择器组件 - 创建食材行适配器处理子列表渲染 - 更新表单布局和样式资源文件
This commit is contained in:
@@ -11,6 +11,7 @@ import android.text.style.ForegroundColorSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -57,9 +58,11 @@ class FormFieldAdapter(
|
||||
b.tvLabel.text = buildLabelSpannable(item.label, item.required)
|
||||
|
||||
// 先全部隐藏,再按类型显示对应控件
|
||||
b.flInputArea.gone()
|
||||
b.etInput.gone()
|
||||
b.flDropdown.gone()
|
||||
b.flDatePicker.gone()
|
||||
b.llChildren.gone()
|
||||
|
||||
// 移除旧的 TextWatcher,防止 RecyclerView 复用时错误触发
|
||||
(b.etInput.tag as? TextWatcher)?.let { b.etInput.removeTextChangedListener(it) }
|
||||
@@ -75,6 +78,15 @@ class FormFieldAdapter(
|
||||
FieldType.FIXED -> bindFixed(b, item)
|
||||
FieldType.DROPDOWN -> bindDropdown(b, item)
|
||||
FieldType.DATE_PICKER -> bindDatePicker(b, item)
|
||||
FieldType.CHILDREN -> bindChildren(b, item)
|
||||
}
|
||||
|
||||
if (item.type == FieldType.CHILDREN) {
|
||||
b.flInputArea.gone()
|
||||
b.llChildren.visible()
|
||||
} else {
|
||||
b.flInputArea.visible()
|
||||
b.llChildren.gone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,4 +201,54 @@ class FormFieldAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
/** 绑定 CHILDREN 类型:渲染子列表(表头 + 嵌套 RecyclerView + 添加按钮) */
|
||||
private fun bindChildren(b: ListItemFormFieldBinding, item: FormField) {
|
||||
b.llChildren.visible()
|
||||
b.tvAddChild.text = item.childAddLabel ?: "+ 添加"
|
||||
|
||||
// 初始化嵌套 RecyclerView
|
||||
if (b.rvChildren.adapter == null) {
|
||||
b.rvChildren.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
b.rvChildren.adapter = createRowAdapter(b, item)
|
||||
|
||||
// 添加按钮点击
|
||||
b.tvAddChild.setOnClickListener {
|
||||
item.children?.let { template ->
|
||||
val newRow = template.map { field ->
|
||||
FormField(
|
||||
label = field.label,
|
||||
type = field.type,
|
||||
apiKey = field.apiKey,
|
||||
extraApiKeys = field.extraApiKeys,
|
||||
required = field.required,
|
||||
hint = field.hint,
|
||||
options = field.options,
|
||||
submitValueId = field.submitValueId
|
||||
)
|
||||
}.toMutableList()
|
||||
item.childrenRows.add(newRow)
|
||||
b.rvChildren.adapter?.notifyItemInserted(item.childrenRows.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建子列表行 Adapter */
|
||||
private fun createRowAdapter(b: ListItemFormFieldBinding, item: FormField): IngredientRowAdapter {
|
||||
return IngredientRowAdapter(
|
||||
rows = item.childrenRows,
|
||||
onDelete = onDelete@{ position ->
|
||||
val adapter = b.rvChildren.adapter as? IngredientRowAdapter ?: return@onDelete
|
||||
item.childrenRows.removeAt(position)
|
||||
adapter.notifyItemRemoved(position)
|
||||
if (position < item.childrenRows.size) {
|
||||
adapter.notifyItemRangeChanged(position, item.childrenRows.size - position)
|
||||
}
|
||||
},
|
||||
onChildClick = { _, _, _ ->
|
||||
// 子字段值已直接更新到 row 的 FormField 中,无需额外操作
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.shuwei.dish.match.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
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.ListItemIngredientRowBinding
|
||||
import com.shuwei.dish.match.dialog.DropdownPopup
|
||||
import com.shuwei.dish.match.model.FormField
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
import com.shuwei.dish.match.utils.ext.hideKeyboard
|
||||
|
||||
/**
|
||||
* 食材行 Adapter,用于「包含食材」子列表的嵌套渲染
|
||||
* @param context Activity 上下文
|
||||
* @param rows 每行包含多个 FormField,对应溯源码、食材名称、分类、用量
|
||||
* @param onDelete 删除行回调
|
||||
* @param onChildClick 子字段点击回调(如下拉框点击)
|
||||
*/
|
||||
class IngredientRowAdapter(
|
||||
rows: MutableList<MutableList<FormField>>,
|
||||
private val onDelete: (Int) -> Unit,
|
||||
private val onChildClick: (Int, Int, FormField) -> Unit
|
||||
) : BaseQuickAdapter<MutableList<FormField>, IngredientRowAdapter.VH>(rows) {
|
||||
|
||||
inner class VH(val binding: ListItemIngredientRowBinding) : QuickViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
|
||||
val binding = ListItemIngredientRowBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
return VH(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: VH, position: Int, item: MutableList<FormField>?) {
|
||||
item ?: return
|
||||
val b = holder.binding
|
||||
|
||||
// 假设 children 模板顺序:[溯源码(TEXT), 食材名称(DROPDOWN), 分类(DROPDOWN), 用量(TEXT)]
|
||||
val traceCodeField = item.getOrNull(0)
|
||||
val materNameField = item.getOrNull(1)
|
||||
val classifyField = item.getOrNull(2)
|
||||
val amountField = item.getOrNull(3)
|
||||
|
||||
// 溯源码 - TEXT
|
||||
traceCodeField?.let { field ->
|
||||
b.etTraceCode.setText(field.value)
|
||||
b.etTraceCode.hint = field.hint.ifBlank { field.label }
|
||||
(b.etTraceCode.tag as? TextWatcher)?.let { b.etTraceCode.removeTextChangedListener(it) }
|
||||
val watcher = object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
field.value = s?.toString() ?: ""
|
||||
}
|
||||
}
|
||||
b.etTraceCode.addTextChangedListener(watcher)
|
||||
b.etTraceCode.tag = watcher
|
||||
}
|
||||
|
||||
// 食材名称 - DROPDOWN
|
||||
materNameField?.let { field ->
|
||||
b.tvMaterName.hint = field.hint.ifBlank { "请选择${field.label}" }
|
||||
b.tvMaterName.text = field.value.ifBlank { null }
|
||||
b.flMaterName.setOnClickListener { v ->
|
||||
v.hideKeyboard()
|
||||
showDropdown(b.flMaterName, field, b.tvMaterName, holder.getAdapterPosition(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 分类 - DROPDOWN
|
||||
classifyField?.let { field ->
|
||||
b.tvClassify.hint = field.hint.ifBlank { "请选择${field.label}" }
|
||||
b.tvClassify.text = field.value.ifBlank { null }
|
||||
b.flClassify.setOnClickListener { v ->
|
||||
v.hideKeyboard()
|
||||
showDropdown(b.flClassify, field, b.tvClassify, holder.getAdapterPosition(), 2)
|
||||
}
|
||||
}
|
||||
|
||||
// 用量 - TEXT
|
||||
amountField?.let { field ->
|
||||
b.etAmount.setText(field.value)
|
||||
b.etAmount.hint = field.hint.ifBlank { field.label }
|
||||
(b.etAmount.tag as? TextWatcher)?.let { b.etAmount.removeTextChangedListener(it) }
|
||||
val watcher = object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
field.value = s?.toString() ?: ""
|
||||
}
|
||||
}
|
||||
b.etAmount.addTextChangedListener(watcher)
|
||||
b.etAmount.tag = watcher
|
||||
}
|
||||
|
||||
// 删除按钮
|
||||
b.tvRemove.setOnClickListener {
|
||||
val pos = holder.layoutPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
onDelete(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 显示下拉弹出框 */
|
||||
private fun showDropdown(
|
||||
anchorView: ViewGroup,
|
||||
field: FormField,
|
||||
valueView: TextView,
|
||||
rowPosition: Int,
|
||||
childIndex: Int
|
||||
) {
|
||||
DropdownPopup(
|
||||
context = context,
|
||||
list = field.options.toMutableList(),
|
||||
popWidth = anchorView.width,
|
||||
popHeight = kotlin.math.min(field.options.size.coerceAtLeast(1), 4) * 50.dp
|
||||
) { dictType ->
|
||||
field.value = dictType.value ?: ""
|
||||
field.valueId = dictType.id ?: ""
|
||||
valueView.text = field.value
|
||||
// 回调通知外部更新
|
||||
onChildClick(rowPosition, childIndex, field)
|
||||
}.also {
|
||||
it.bgLayout = anchorView
|
||||
it.showAsDropDown(anchorView)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class DropdownPopup(
|
||||
|
||||
override fun showAsDropDown(anchor: View?) {
|
||||
super.showAsDropDown(anchor)
|
||||
bgLayout?.setBackgroundResource(R.drawable.bg_white_stroke_blue)
|
||||
bgLayout?.setBackgroundResource(R.drawable.shape_green_stroke)
|
||||
arrowImage?.setImageResource(R.mipmap.ic_triangle_up)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ enum class FieldType {
|
||||
/** 日期选择弹窗 */
|
||||
DATE_PICKER,
|
||||
/** 固定值,不可编辑 */
|
||||
FIXED
|
||||
FIXED,
|
||||
/** 子列表容器,用于动态增减行(如"包含食材") */
|
||||
CHILDREN
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,6 +32,9 @@ enum class FieldType {
|
||||
* @param value 当前显示值/输入值;DATE_PICKER 存 yyyy-MM-dd 显示格式
|
||||
* @param valueId DATE_PICKER 存 ISO 格式 yyyy-MM-dd'T'HH:mm:ss
|
||||
* @param extraValues 下拉选中后按 extraApiKeys 映射存储的提交值,key=接口参数名
|
||||
* @param children 子字段模板(CHILDREN 类型使用),每行按此模板创建一组字段
|
||||
* @param childAddLabel 添加按钮文案(CHILDREN 类型使用),如 "+ 添加食材"
|
||||
* @param childrenRows 子列表实际数据(CHILDREN 类型使用),每行是一个 List<FormField>
|
||||
*/
|
||||
data class FormField(
|
||||
val label: String,
|
||||
@@ -43,5 +48,8 @@ data class FormField(
|
||||
val submitValueId: Boolean = false,
|
||||
var value: String = "",
|
||||
var valueId: String = "",
|
||||
val extraValues: MutableMap<String, String> = mutableMapOf()
|
||||
val extraValues: MutableMap<String, String> = mutableMapOf(),
|
||||
val children: List<FormField>? = null,
|
||||
val childAddLabel: String? = null,
|
||||
val childrenRows: MutableList<MutableList<FormField>> = mutableListOf()
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.FormFieldAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.databinding.ActivityCleanPackBinding
|
||||
import com.shuwei.dish.match.model.DictType
|
||||
import com.shuwei.dish.match.model.FieldType
|
||||
import com.shuwei.dish.match.model.FormField
|
||||
import com.shuwei.dish.match.utils.ext.dp
|
||||
@@ -170,12 +171,143 @@ class CleanPackActivity : BaseActivity() {
|
||||
|
||||
/**
|
||||
* 初始化餐品净菜包装表单字段
|
||||
* TODO: 由用户提供具体字段数据
|
||||
* 对应接口 NutSupMealPackageDTO
|
||||
*/
|
||||
private fun initMealPackFields() {
|
||||
fields.clear()
|
||||
// 待填充
|
||||
formAdapter.submitList(fields)
|
||||
|
||||
// 包装餐品
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装餐品", type = FieldType.DROPDOWN,
|
||||
apiKey = "foodId", required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "1", type = "宫保鸡丁"),
|
||||
DictType(id = "2", value = "2", type = "鱼香肉丝"),
|
||||
DictType(id = "3", value = "3", type = "红烧茄子"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// 包装规格
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装规格", type = FieldType.DROPDOWN,
|
||||
apiKey = "spec", required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "500g/盒", type = "500g/盒"),
|
||||
DictType(id = "2", value = "1kg/盒", type = "1kg/盒"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// 包装方式
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装方式", type = FieldType.DROPDOWN,
|
||||
apiKey = "packageMethod", required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "真空包装", type = "真空包装"),
|
||||
DictType(id = "2", value = "气调包装", type = "气调包装"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// 包装份数
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装份数", type = FieldType.INTEGER,
|
||||
apiKey = "quantity", required = true, hint = "请输入份数"
|
||||
)
|
||||
)
|
||||
|
||||
// 包含食材(子列表容器)
|
||||
val ingredientTemplate = listOf(
|
||||
FormField(label = "食材溯源码", type = FieldType.TEXT, required = true, hint = "溯源码"),
|
||||
FormField(
|
||||
label = "食材名称", type = FieldType.DROPDOWN, required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "土豆", type = "土豆"),
|
||||
DictType(id = "2", value = "鸡肉", type = "鸡肉"),
|
||||
DictType(id = "3", value = "青椒", type = "青椒"),
|
||||
)
|
||||
),
|
||||
FormField(
|
||||
label = "分类", type = FieldType.DROPDOWN, required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "蔬菜类", type = "蔬菜类"),
|
||||
DictType(id = "2", value = "肉禽类", type = "肉禽类"),
|
||||
DictType(id = "3", value = "水产类", type = "水产类"),
|
||||
)
|
||||
),
|
||||
FormField(label = "每份用量", type = FieldType.TEXT, required = true, hint = "如 120g"),
|
||||
)
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包含食材", type = FieldType.CHILDREN,
|
||||
required = true,
|
||||
children = ingredientTemplate,
|
||||
childAddLabel = "+ 添加食材"
|
||||
)
|
||||
)
|
||||
|
||||
// 包装日期
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装日期", type = FieldType.DATE_PICKER,
|
||||
apiKey = "packageDate", required = true
|
||||
)
|
||||
)
|
||||
|
||||
// 保质期至
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "保质期至", type = FieldType.DATE_PICKER,
|
||||
apiKey = "expiryDate", required = true
|
||||
)
|
||||
)
|
||||
|
||||
// 存放温度
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "存放温度(℃)", type = FieldType.DECIMAL,
|
||||
apiKey = "storageTemp", required = false, hint = "如 3.8"
|
||||
)
|
||||
)
|
||||
|
||||
// 包装人
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "包装人", type = FieldType.TEXT,
|
||||
apiKey = "operator", required = false, hint = "请输入包装人"
|
||||
)
|
||||
)
|
||||
|
||||
// 终端设备
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "终端设备", type = FieldType.DROPDOWN,
|
||||
apiKey = "deviceId", required = false,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "1", type = "包装机-01"),
|
||||
DictType(id = "2", value = "2", type = "包装机-02"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// 操作类型
|
||||
fields.add(
|
||||
FormField(
|
||||
label = "操作类型", type = FieldType.DROPDOWN,
|
||||
apiKey = "opType", required = true,
|
||||
options = listOf(
|
||||
DictType(id = "1", value = "1", type = "设备自动"),
|
||||
DictType(id = "2", value = "2", type = "人工录入"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
formAdapter.submitList(fields.filter { !it.hidden })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke android:color="#FFDCDCF0" android:width="1dp"/>
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/white"/>
|
||||
<stroke android:color="#FF0032C8" android:width="2dp"/>
|
||||
<corners android:radius="10dp"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#30000000">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#99FFFFFF"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -4,7 +4,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/ripple_effect_light">
|
||||
android:background="@drawable/ripple_effect_light3">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDropdown"
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="10dp">
|
||||
android:paddingVertical="10dp"
|
||||
tools:background="@color/white">
|
||||
|
||||
<!-- 字段标签,必填项红色星号由 Adapter 通过 SpannableString 追加 -->
|
||||
<TextView
|
||||
@@ -18,11 +19,135 @@
|
||||
android:textStyle="bold"
|
||||
tools:text="食材名称" />
|
||||
|
||||
<!-- CHILDREN 类型:子列表容器 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/llChildren"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<!-- 子列表标题行 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@drawable/bg_rect_header">
|
||||
|
||||
<!-- 食材溯源码表头 -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:gravity="center"
|
||||
android:text="食材溯源码"
|
||||
android:textColor="#FF141428"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FFDCDCF0"/>
|
||||
<!-- 食材名称表头 -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginHorizontal="2dp"
|
||||
android:gravity="center"
|
||||
android:text="食材名称"
|
||||
android:textColor="#FF141428"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FFDCDCF0"/>
|
||||
|
||||
<!-- 分类表头 -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginHorizontal="2dp"
|
||||
android:gravity="center"
|
||||
android:text="分类"
|
||||
android:textColor="#FF141428"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FFDCDCF0"/>
|
||||
|
||||
<!-- 每份用量表头 -->
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginStart="2dp"
|
||||
android:maxLines="1"
|
||||
android:gravity="center"
|
||||
android:text="每份用量"
|
||||
android:textColor="#FF141428"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FFDCDCF0"/>
|
||||
|
||||
<!-- 操作表头 -->
|
||||
<TextView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="match_parent"
|
||||
android:text="操作"
|
||||
android:gravity="center"
|
||||
android:textColor="#FF141428"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 嵌套 RecyclerView -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvChildren"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="never"
|
||||
tools:listitem="@layout/list_item_ingredient_row"/>
|
||||
|
||||
<!-- 添加按钮 -->
|
||||
<TextView
|
||||
android:id="@+id/tvAddChild"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:paddingVertical="5dp"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:textColor="#FF0066CC"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:text="+ 添加食材"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 输入区域容器,三种控件叠放,按 FieldType 切换 visibility -->
|
||||
<FrameLayout
|
||||
android:id="@+id/flInputArea"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginHorizontal="12dp">
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<!-- TEXT / NUMBER / FIXED 类型:EditText -->
|
||||
<EditText
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?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="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="4dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<!-- 食材溯源码 -->
|
||||
<EditText
|
||||
android:id="@+id/etTraceCode"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="@drawable/bg_white_radius10_stroke2"
|
||||
android:hint="溯源码"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:textColor="#FF141428"
|
||||
android:textColorHint="#FF96A0AA"
|
||||
android:textSize="16sp"
|
||||
tools:ignore="Autofill,TextFields" />
|
||||
|
||||
<!-- 食材名称 -->
|
||||
<FrameLayout
|
||||
android:id="@+id/flMaterName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="@drawable/bg_white_radius10_stroke2">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMaterName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="#FF141428"
|
||||
android:textColorHint="#FF96A0AA"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:src="@mipmap/ic_triangle_down"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<!-- 分类 -->
|
||||
<FrameLayout
|
||||
android:id="@+id/flClassify"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="@drawable/bg_white_radius10_stroke2">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvClassify"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="#FF141428"
|
||||
android:textColorHint="#FF96A0AA"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:src="@mipmap/ic_triangle_down"
|
||||
tools:ignore="ContentDescription" />
|
||||
</FrameLayout>
|
||||
|
||||
<!-- 每份用量 -->
|
||||
<EditText
|
||||
android:id="@+id/etAmount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_white_radius10_stroke2"
|
||||
android:hint="如 120g"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:textColor="#FF141428"
|
||||
android:textColorHint="#FF96A0AA"
|
||||
android:textSize="16sp"
|
||||
tools:ignore="Autofill,TextFields" />
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<TextView
|
||||
android:id="@+id/tvRemove"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:gravity="center"
|
||||
android:text="×"
|
||||
android:textColor="#FF96A0AA"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user