refactor(ui): 重构主界面食物列表布局和支付模式切换功能

- 将原有的RecyclerView替换为FrameLayout容器,实现动态布局加载
- 新增layout_main_food_list.xml和layout_main_food_list2.xml两个布局文件
- 实现联合支付和独立支付两种模式下的不同UI展示
- 集成食物详情显示功能,通过include方式引入layout_eat_detail.xml
- 更新数据绑定逻辑,支持两种支付模式下的食物列表显示
- 迁移SharedPreferences操作至SpTool工具类统一管理
- 优化食物识别结果显示逻辑和搜索按钮状态控制
- 重构RecyclerView初始化和适配器设置代码结构
This commit is contained in:
2026-04-24 15:37:57 +08:00
parent e3b01ff789
commit 03c5aee785
8 changed files with 178 additions and 76 deletions
@@ -13,6 +13,7 @@ import android.text.TextUtils
import android.view.Display import android.view.Display
import android.view.View import android.view.View
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import android.widget.TextView
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.camera.core.CameraSelector import androidx.camera.core.CameraSelector
@@ -22,13 +23,18 @@ import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import com.sw.dualscreen.GlobalData import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.adapter.MainFoodListAdapter import com.sw.dualscreen.adapter.MainFoodListAdapter
import com.sw.dualscreen.databinding.ActivityMainBinding import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.databinding.LayoutEatDetailBinding
import com.sw.dualscreen.databinding.LayoutMainFoodList2Binding
import com.sw.dualscreen.databinding.LayoutMainFoodListBinding
import com.sw.dualscreen.dialog.EnvSwitchDialog import com.sw.dualscreen.dialog.EnvSwitchDialog
import com.sw.dualscreen.dialog.RemindDialog import com.sw.dualscreen.dialog.RemindDialog
import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.dp
@@ -180,6 +186,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// SPUtil.getInstance().get(GlobalKey.KEY_SETTLEMENT_MODE, 1) // SPUtil.getInstance().get(GlobalKey.KEY_SETTLEMENT_MODE, 1)
// } // }
private lateinit var rvFoodList: RecyclerView
private lateinit var tvToSearch: TextView
lateinit var layoutEatDetailBinding: LayoutEatDetailBinding
override fun getViewModel(): BaseViewModel { override fun getViewModel(): BaseViewModel {
return viewModel return viewModel
} }
@@ -202,25 +212,66 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
initData() initData()
} }
private fun initLayoutEatDetailBinding(mode: Int) {
binding.flFoodList.removeAllViews()
if (mode == 0) {
//联合支付
val b = LayoutMainFoodList2Binding.inflate(layoutInflater, binding.flFoodList, true)
rvFoodList = b.rvFoodList
tvToSearch = b.tvToSearch
layoutEatDetailBinding = b.detailInclude
layoutEatDetailBinding.llFoodTitle.gone()
// layoutEatDetailBinding.root.invisible()
} else {
//独立支付
val b = LayoutMainFoodListBinding.inflate(layoutInflater, binding.flFoodList, true)
rvFoodList = b.rvFoodList
tvToSearch = b.tvToSearch
layoutEatDetailBinding = b.detailInclude
layoutEatDetailBinding.llFoodTitle.gone()
layoutEatDetailBinding.root.gone()
}
tvToSearch.setOnClickListener {
bottomSheetDialog = CustomBottomSheetDialog.newInstance(viewModel) {
checkedItem = it
it.photoUri = null
adapter.items.forEachIndexed { index, info ->
adapter.items[index].isChecked = false
}
adapter.notifyDataSetChanged()
resetSelectedFood(it)
}
bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog")
}
rvFoodList.let {
it.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)
it.adapter = adapter
}
}
private fun initData() { private fun initData() {
startFaceTask() startFaceTask()
} }
private fun initView() { private fun initView() {
initLayoutEatDetailBinding(SpTool.settlementMode)
viewModel.getDeviceConfig { deviceConfig -> viewModel.getDeviceConfig { deviceConfig ->
runOnUiThread { runOnUiThread {
if (deviceConfig == null) { if (deviceConfig == null) {
ToastUtils.showToast("获取设备配置数据失败") ToastUtils.showToast("获取设备配置数据失败")
initLayoutEatDetailBinding(SpTool.settlementMode)
return@runOnUiThread return@runOnUiThread
} }
//结算模式:1-独立支付,2-联合结算 //结算模式:1-独立支付,2-联合结算
settlementMode = if (deviceConfig.payType == 2) 0 else 1 settlementMode = if (deviceConfig.payType == 2) 0 else 1
SPUtil.getInstance().put(GlobalKey.KEY_SETTLEMENT_MODE, settlementMode) SpTool.settlementMode = settlementMode
GlobalData.appId = deviceConfig.arcsoftAppId ?: "" GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: "" GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: "" GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
viewModel.activeEngine() viewModel.activeEngine()
initLayoutEatDetailBinding(settlementMode)
} }
} }
updateDateTime() updateDateTime()
@@ -264,23 +315,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
} }
} }
binding.previewView.clipToOutline = true binding.previewView.clipToOutline = true
binding.tvToSearch.setOnClickListener {
bottomSheetDialog = CustomBottomSheetDialog.newInstance(viewModel) {
checkedItem = it
it.photoUri = null
adapter.items.forEachIndexed { index, info ->
adapter.items[index].isChecked = false
}
adapter.notifyDataSetChanged()
resetSelectedFood(it)
}
bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog")
}
binding.recyclerview.let {
it.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)
it.adapter = adapter
}
binding.tvFoodName.setOnClickListener { binding.tvFoodName.setOnClickListener {
SensorScaleUtils.zero() SensorScaleUtils.zero()
} }
@@ -545,7 +579,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
log("registerDataChange识别后查询接口数据:$queryData,识别数据:$recData") log("registerDataChange识别后查询接口数据:$queryData,识别数据:$recData")
if (list.isEmpty()) { if (list.isEmpty()) {
foodRecognizeState = false foodRecognizeState = false
binding.tvToSearch.let { tvToSearch.let {
it.text = "未查询到,手动搜索" it.text = "未查询到,手动搜索"
it.visible() it.visible()
} }
@@ -571,7 +605,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// } // }
adapter.submitList(list) adapter.submitList(list)
binding.recyclerview.visible() rvFoodList.visible()
checkedItem = list[0].also { checkedItem = list[0].also {
it.photoUri = lastPhotoUri it.photoUri = lastPhotoUri
@@ -582,10 +616,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
// lastPhotoUri = null // lastPhotoUri = null
LightManager.closeRedLight() LightManager.closeRedLight()
binding.tvToSearch.let { tvToSearch.let {
it.text = "以上都不是,手动搜索" it.text = "以上都不是,手动搜索"
it.visible() it.visible()
} }
log("registerDataChange识别完成:visible=${rvFoodList.isVisible},count=${rvFoodList.childCount}")
} }
private fun setupCamera() { private fun setupCamera() {
@@ -756,9 +791,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun clearRecognizeFood() { fun clearRecognizeFood() {
log("clearRecognizeFood") log("clearRecognizeFood")
binding.recyclerview.invisible() rvFoodList.invisible()
layoutEatDetailBinding.root.invisible()
adapter.submitList(null) adapter.submitList(null)
binding.tvToSearch.gone() tvToSearch.gone()
binding.previewView.visible() binding.previewView.visible()
binding.ivImg.gone() binding.ivImg.gone()
@@ -1294,7 +1330,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
//binding.layoutRescan.visibility = View.VISIBLE //binding.layoutRescan.visibility = View.VISIBLE
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.tvToSearch.let { tvToSearch.let {
it.text = "未识别到,手动搜索" it.text = "未识别到,手动搜索"
it.visible() it.visible()
} }
@@ -9,6 +9,7 @@ import com.sw.dualscreen.model.response.ChargeModeEvent
import com.sw.dualscreen.model.response.ResetRecognizeEvent import com.sw.dualscreen.model.response.ResetRecognizeEvent
import com.sw.dualscreen.sdk.SensorScaleUtils import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.SPUtil import com.sw.dualscreen.utils.SPUtil
import com.sw.dualscreen.utils.SpTool
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -23,8 +24,8 @@ class BusinessFragment: BaseFragment<FragmentBusinessBinding>() {
binding.rgSettlement.let { binding.rgSettlement.let {
//val settlementMode = if (binding.rgSettlement.checkedRadioButtonId == R.id.rbJointPayment) 0 else 1 //val settlementMode = if (binding.rgSettlement.checkedRadioButtonId == R.id.rbJointPayment) 0 else 1
val mode = SPUtil.getInstance().get(GlobalKey.KEY_SETTLEMENT_MODE, 1) //val mode = SPUtil.getInstance().get(GlobalKey.KEY_SETTLEMENT_MODE, 1)
it.check(if (mode == 0) R.id.rbJointPayment else R.id.rbIndependentPayment) it.check(if (SpTool.settlementMode == 0) R.id.rbJointPayment else R.id.rbIndependentPayment)
binding.rbJointPayment.isEnabled = false binding.rbJointPayment.isEnabled = false
binding.rbIndependentPayment.isEnabled = false binding.rbIndependentPayment.isEnabled = false
} }
@@ -16,11 +16,11 @@ import android.view.ViewTreeObserver
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.arcsoft.face.ErrorInfo import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.BuildConfig import com.sw.dualscreen.BuildConfig
import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.GlobalKey
@@ -64,7 +64,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.text.DecimalFormat
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -327,6 +326,7 @@ class MainScreenPresentation(
loadOrderList(userId) { loadOrderList(userId) {
loadUserNutritionData(userId) loadUserNutritionData(userId)
} }
activity.layoutEatDetailBinding.root.visible()
} else { } else {
//独立支付 //独立支付
loadUserNutritionData(userId) loadUserNutritionData(userId)
@@ -776,10 +776,14 @@ class MainScreenPresentation(
val fruitsVegetables = energy.fruitsVegetables val fruitsVegetables = energy.fruitsVegetables
val meatEggs = energy.meatEggs val meatEggs = energy.meatEggs
binding.detailInclude.tvTotalCalorie.text = "总热量:${totalKcal.roundedDecimalPlace(1)}千卡" val showTotalCalorie = "总热量:${totalKcal.roundedDecimalPlace(1)}千卡"
binding.detailInclude.tvTotalCalorie.text = showTotalCalorie
activity.layoutEatDetailBinding.tvTotalCalorie.text = showTotalCalorie
val totalWeight = (userNutrition?.eatWeightSum ?: 0.0) + weight val totalWeight = (userNutrition?.eatWeightSum ?: 0.0) + weight
binding.detailInclude.tvTotalWeight.text = "总重量:${totalWeight.roundedDecimalPlace(1)}" val showTotalWeight = "总重量:${totalWeight.roundedDecimalPlace(1)}"
binding.detailInclude.tvTotalWeight.text = showTotalWeight
activity.layoutEatDetailBinding.tvTotalWeight.text = showTotalWeight
val include = binding.nutritionInclude val include = binding.nutritionInclude
@@ -1449,6 +1453,16 @@ class MainScreenPresentation(
FoodOrderAdapter(foodOrderList) FoodOrderAdapter(foodOrderList)
} }
private fun initRv(rv: RecyclerView) {
rv.run {
if (adapter == null) {
layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
adapter = foodOrderAdapter
}
}
}
/** /**
* 加载订单列表 * 加载订单列表
*/ */
@@ -1460,13 +1474,8 @@ class MainScreenPresentation(
it.root.updateLayoutParams { it.root.updateLayoutParams {
height = activity.screenSize[1] / 2 + 120.dp height = activity.screenSize[1] / 2 + 120.dp
} }
it.rvFoodList.run { initRv(it.rvFoodList)
if (adapter == null) { initRv(activity.layoutEatDetailBinding.rvFoodList)
layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
adapter = foodOrderAdapter
}
}
userViewModel.getFoodOrderList(userId) { model -> userViewModel.getFoodOrderList(userId) { model ->
activity.runOnUiThread { activity.runOnUiThread {
if (model == null) return@runOnUiThread if (model == null) return@runOnUiThread
@@ -17,13 +17,13 @@ object SpTool {
var lastFaceTimestamp: Long var lastFaceTimestamp: Long
get() = spUtil?.get(LAST_FACE_TIMESTAMP, 0L)?:0L get() = spUtil?.get(LAST_FACE_TIMESTAMP, 0L) ?: 0L
set(timestamp) { set(timestamp) {
spUtil?.put(LAST_FACE_TIMESTAMP, timestamp) spUtil?.put(LAST_FACE_TIMESTAMP, timestamp)
} }
var firstGetFace: Boolean var firstGetFace: Boolean
get() = spUtil?.get(IS_FIRST_GET_FACE, true)?:true get() = spUtil?.get(IS_FIRST_GET_FACE, true) ?: true
set(value) { set(value) {
spUtil?.boolean(IS_FIRST_GET_FACE, value) spUtil?.boolean(IS_FIRST_GET_FACE, value)
} }
@@ -33,5 +33,10 @@ object SpTool {
set(value) { set(value) {
spUtil?.put(GlobalKey.KEY_BASE_URL, value) spUtil?.put(GlobalKey.KEY_BASE_URL, value)
} }
var settlementMode: Int
get() = spUtil?.get(GlobalKey.KEY_SETTLEMENT_MODE, 0) ?: 0
set(value) {
spUtil?.put(GlobalKey.KEY_SETTLEMENT_MODE, value)
}
} }
+4 -37
View File
@@ -92,51 +92,18 @@
</FrameLayout> </FrameLayout>
<androidx.recyclerview.widget.RecyclerView <FrameLayout
android:id="@+id/recyclerview" android:id="@+id/flFoodList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginHorizontal="14dp" android:layout_weight="1"/>
android:layout_marginTop="42dp"
android:layout_weight="1"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="8"
tools:listitem="@layout/list_item_search_food" />
<TextView
android:id="@+id/tvToSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="38dp"
android:layout_marginBottom="0dp"
android:padding="10dp"
android:text="以上都不是,手动搜索"
android:textColor="#FFFF3232"
android:textSize="31sp"
android:textStyle="bold"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="center">
<TextView
android:id="@+id/tvWeightRealInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="12sp"
tools:text="以上都不是,手动搜索" />
</LinearLayout>
<FrameLayout <FrameLayout
android:id="@+id/flPay" android:id="@+id/flPay"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/white" android:background="@color/white"
android:layout_marginTop="45dp"
android:visibility="gone"> android:visibility="gone">
<androidx.appcompat.widget.AppCompatButton <androidx.appcompat.widget.AppCompatButton
@@ -8,6 +8,7 @@
tools:ignore="HardcodedText,UseCompatTextViewDrawableXml"> tools:ignore="HardcodedText,UseCompatTextViewDrawableXml">
<FrameLayout <FrameLayout
android:id="@+id/llFoodTitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="80dp"> android:layout_height="80dp">
@@ -54,6 +55,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:overScrollMode="never"
tools:listitem="@layout/layout_food_list_header" /> tools:listitem="@layout/layout_food_list_header" />
<LinearLayout <LinearLayout
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFoodList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="14dp"
android:layout_marginTop="42dp"
android:layout_weight="1"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="8"
tools:listitem="@layout/list_item_search_food" />
<TextView
android:id="@+id/tvToSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="38dp"
android:layout_gravity="center_horizontal"
android:padding="10dp"
tools:text="以上都不是,手动搜索"
android:textColor="#FFFF3232"
android:textSize="31sp"
android:textStyle="bold"/>
<include
android:id="@+id/detailInclude"
layout="@layout/layout_eat_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="14dp"
android:visibility="gone"/>
</LinearLayout>
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFoodList"
android:layout_width="match_parent"
android:layout_height="264dp"
android:layout_marginHorizontal="14dp"
android:layout_marginTop="42dp"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="8"
tools:listitem="@layout/list_item_search_food" />
<TextView
android:id="@+id/tvToSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="38dp"
android:layout_gravity="center_horizontal"
android:padding="10dp"
tools:text="以上都不是,手动搜索"
android:textColor="#FFFF3232"
android:textSize="31sp"
android:textStyle="bold"/>
<include
android:id="@+id/detailInclude"
layout="@layout/layout_eat_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="14dp"/>
</LinearLayout>