feat(fragment): 新增调料选择弹窗并绑定格子点击交互
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,16 @@ class Seasoning18GridAdapter : BaseQuickAdapter<SeasoningEntity, Seasoning18Grid
|
|||||||
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-"
|
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指定位置的调料名称并刷新对应格子
|
||||||
|
* @param position 格子索引
|
||||||
|
* @param name 新的调料名称
|
||||||
|
*/
|
||||||
|
fun updateItemName(position: Int, name: String) {
|
||||||
|
items.getOrNull(position)?.goodsName = name
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 SCALE_ORDER_18 的 sort 顺序更新数据,空位用哨兵填充
|
* 按 SCALE_ORDER_18 的 sort 顺序更新数据,空位用哨兵填充
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ class Seasoning22GridAdapter(
|
|||||||
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-"
|
holder.b.tvGoodsName.text = item?.goodsName?.takeIf { it.isNotBlank() } ?: "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指定位置的调料名称并刷新对应格子
|
||||||
|
* @param position 格子索引
|
||||||
|
* @param name 新的调料名称
|
||||||
|
*/
|
||||||
|
fun updateItemName(position: Int, name: String) {
|
||||||
|
items.getOrNull(position)?.goodsName = name
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 SCALE_ORDER_22 的 sort 顺序更新数据,空位用哨兵填充
|
* 按 SCALE_ORDER_22 的 sort 顺序更新数据,空位用哨兵填充
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package com.shuwei.dish.match.dialog
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.core.view.isEmpty
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.shuwei.dish.match.R
|
||||||
|
import com.shuwei.dish.match.adapter.SeasoningSearchAdapter
|
||||||
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
|
import com.shuwei.dish.match.databinding.DialogSeasoningSelectBinding
|
||||||
|
import com.shuwei.dish.match.entity.SeasoningEntity
|
||||||
|
import com.shuwei.dish.match.utils.KeyboardUtil
|
||||||
|
import com.shuwei.dish.match.utils.ext.addOnActionSearchListener
|
||||||
|
import com.shuwei.dish.match.utils.ext.toast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调料选择弹窗,不含重量显示,继承 BottomSheetDialog 确保只初始化一次
|
||||||
|
* @param activity 宿主 Activity
|
||||||
|
* @param clickIndex 点击的调料槽位索引
|
||||||
|
* @param onItemSelected 用户点击某一调料时的回调
|
||||||
|
*/
|
||||||
|
class SeasoningSelectDialog(
|
||||||
|
private val activity: BaseActivity,
|
||||||
|
private val clickIndex: Int,
|
||||||
|
private val onItemSelected: (item: SeasoningEntity) -> Unit
|
||||||
|
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "SeasoningSelectDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val binding = DialogSeasoningSelectBinding.inflate(LayoutInflater.from(activity))
|
||||||
|
private val list = mutableListOf<SeasoningEntity>()
|
||||||
|
private val adapter = SeasoningSearchAdapter(list).apply {
|
||||||
|
setOnItemClickListener { _, _, position ->
|
||||||
|
list[position].isClicked = true
|
||||||
|
notifyItemChanged(position)
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
onItemSelected(list[position])
|
||||||
|
dismiss()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var goodsName: String? = null
|
||||||
|
private var pageNo = 1
|
||||||
|
private val pageSize = 50
|
||||||
|
|
||||||
|
init {
|
||||||
|
setContentView(binding.root)
|
||||||
|
setCancelable(true)
|
||||||
|
behavior.skipCollapsed = false
|
||||||
|
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
|
||||||
|
window?.setGravity(Gravity.BOTTOM)
|
||||||
|
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
window?.setWindowAnimations(R.style.DialogSoftInputAnimation)
|
||||||
|
window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||||
|
|
||||||
|
setOnDismissListener {
|
||||||
|
activity.hideStatusBar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框:清空时重置列表
|
||||||
|
binding.etSheetInput.run {
|
||||||
|
hint = "输入调料名称"
|
||||||
|
addTextChangedListener(
|
||||||
|
onTextChanged = { text, _, _, _ -> goodsName = text.toString() },
|
||||||
|
afterTextChanged = {
|
||||||
|
if (it.isNullOrBlank()) {
|
||||||
|
list.clear()
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
addOnActionSearchListener { searchGoods(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecyclerView 初始化及滑动冲突处理
|
||||||
|
binding.recyclerView.run {
|
||||||
|
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
|
||||||
|
adapter = this@SeasoningSelectDialog.adapter
|
||||||
|
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(rv: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(rv, dx, dy)
|
||||||
|
// 解决 RecyclerView 与 SmartRefreshLayout 滑动冲突
|
||||||
|
val topRowVerticalPosition = if (rv.isEmpty()) 0 else rv.getChildAt(0).top
|
||||||
|
binding.refreshLayout.setNestedScrollingEnabled(topRowVerticalPosition >= 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.refreshLayout.run {
|
||||||
|
setEnableRefresh(false)
|
||||||
|
setEnableLoadMore(false)
|
||||||
|
setOnRefreshListener { pageNo = 1; getGoodsList() }
|
||||||
|
setOnLoadMoreListener { getGoodsList() }
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivSearch.setOnClickListener { searchGoods(it) }
|
||||||
|
binding.root.setOnClickListener { KeyboardUtil.hideKeyboard(it.context, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 弹窗显示时自动加载默认调料列表 */
|
||||||
|
override fun show() {
|
||||||
|
super.show()
|
||||||
|
pageNo = 1
|
||||||
|
getGoodsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发搜索:校验输入、隐藏键盘、发起请求
|
||||||
|
*/
|
||||||
|
private fun searchGoods(v: View) {
|
||||||
|
if (goodsName.isNullOrBlank()) {
|
||||||
|
activity.toast("请${binding.etSheetInput.hint}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pageNo = 1
|
||||||
|
getGoodsList()
|
||||||
|
KeyboardUtil.hideKeyboard(v.context, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求调料列表(临时使用本地模拟数据,正式联调时替换为真实接口)
|
||||||
|
*/
|
||||||
|
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 = "白醋")
|
||||||
|
)
|
||||||
|
loadGoodsList(mockData)
|
||||||
|
|
||||||
|
// val param = mutableMapOf<String, Any>(
|
||||||
|
// "goodsType" to "1",
|
||||||
|
// "placeId" to BaseApp.canteenId,
|
||||||
|
// "pageNum" to pageNo,
|
||||||
|
// "pageSize" to pageSize
|
||||||
|
// )
|
||||||
|
// if (!goodsName.isNullOrBlank()) {
|
||||||
|
// param["goodsName"] = goodsName!!
|
||||||
|
// }
|
||||||
|
// activity.querySeasoningList(param = param, onSuccess = {
|
||||||
|
// loadGoodsList(it)
|
||||||
|
// }, onFailure = { _, msg ->
|
||||||
|
// activity.toast(msg)
|
||||||
|
// finishRefresh()
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将返回数据填充到列表
|
||||||
|
*/
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun loadGoodsList(records: MutableList<SeasoningEntity>?) {
|
||||||
|
finishRefresh()
|
||||||
|
if (records.isNullOrEmpty()) {
|
||||||
|
activity.toast("暂未搜索到调料信息")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pageNo == 1) list.clear()
|
||||||
|
list.addAll(records)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
val isLoadMoreEnable = records.size >= pageSize
|
||||||
|
binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable)
|
||||||
|
if (isLoadMoreEnable) pageNo++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun finishRefresh() {
|
||||||
|
if (pageNo == 1) binding.refreshLayout.finishRefresh()
|
||||||
|
else binding.refreshLayout.finishLoadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import com.shuwei.dish.match.adapter.Seasoning18GridAdapter
|
|||||||
import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
|
import com.shuwei.dish.match.adapter.Seasoning22GridAdapter
|
||||||
import com.shuwei.dish.match.base.BaseFragment
|
import com.shuwei.dish.match.base.BaseFragment
|
||||||
import com.shuwei.dish.match.databinding.FragmentSeasoningConfigBinding
|
import com.shuwei.dish.match.databinding.FragmentSeasoningConfigBinding
|
||||||
|
import com.shuwei.dish.match.dialog.SeasoningSelectDialog
|
||||||
import com.shuwei.dish.match.ui.SettingActivity
|
import com.shuwei.dish.match.ui.SettingActivity
|
||||||
import com.shuwei.dish.match.utils.ext.dp
|
import com.shuwei.dish.match.utils.ext.dp
|
||||||
|
|
||||||
@@ -31,9 +32,32 @@ class SeasoningConfigFragment : BaseFragment<FragmentSeasoningConfigBinding>() {
|
|||||||
settingActivity = activity as SettingActivity
|
settingActivity = activity as SettingActivity
|
||||||
// initViewModel()
|
// initViewModel()
|
||||||
setupRecyclerViews()
|
setupRecyclerViews()
|
||||||
|
bindAdapterClicks()
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 绑定两个 Adapter 的格子点击,弹出调料选择弹窗 */
|
||||||
|
private fun bindAdapterClicks() {
|
||||||
|
adapter22.onItemClick = { _, position ->
|
||||||
|
SeasoningSelectDialog(
|
||||||
|
activity = settingActivity,
|
||||||
|
clickIndex = position,
|
||||||
|
onItemSelected = { item ->
|
||||||
|
adapter22.updateItemName(position, item.goodsName ?: "")
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
adapter18.onItemClick = { _, position ->
|
||||||
|
SeasoningSelectDialog(
|
||||||
|
activity = settingActivity,
|
||||||
|
clickIndex = position,
|
||||||
|
onItemSelected = { item ->
|
||||||
|
adapter18.updateItemName(position, item.goodsName ?: "")
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// /** 初始化 ViewModel */
|
// /** 初始化 ViewModel */
|
||||||
// private fun initViewModel() {
|
// private fun initViewModel() {
|
||||||
// val factory = AppFactory(AppRepository(BaseApp.instance!!.database.appDao()))
|
// val factory = AppFactory(AppRepository(BaseApp.instance!!.database.appDao()))
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout 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="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
tools:background="@color/white"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/viewLine"
|
||||||
|
android:layout_width="90dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:background="@drawable/shape_gray_dc_5" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:layout_marginStart="60dp"
|
||||||
|
android:layout_marginEnd="60dp"
|
||||||
|
android:background="@drawable/shape_white_e6_12_corners"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etSheetInput"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="start|center_vertical"
|
||||||
|
android:background="@null"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:imeOptions="actionSearch"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingStart="30dp"
|
||||||
|
android:paddingEnd="30dp"
|
||||||
|
android:textColor="@color/black666"
|
||||||
|
android:textColorHint="@color/gray_c8"
|
||||||
|
android:textSize="36sp"
|
||||||
|
tools:hint="@string/input_seasoning_name"
|
||||||
|
tools:ignore="Autofill,LabelFor,TextFields" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivSearch"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/ic_search_gray"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
|
android:id="@+id/refreshLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:srlEnableOverScrollDrag="false">
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.header.ClassicsHeader
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
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:minHeight="380dp"
|
||||||
|
android:nestedScrollingEnabled="true"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
app:spanCount="2"
|
||||||
|
tools:itemCount="10"
|
||||||
|
tools:listitem="@layout/list_item_search_goods_info" />
|
||||||
|
|
||||||
|
<com.scwang.smart.refresh.footer.ClassicsFooter
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user