feat(activity): 新增菜品识别功能,重构FoodRecognizeDialog并临时跳过调料配置检查
- 新增 FoodRecognizeDialog(继承 BottomSheetDialog),只初始化一次,暴露 loadData() 方法 - 新增 dialog_food_recognize.xml 布局(标题 + 2列 GridLayoutManager RecyclerView) - PrepareCookActivity 集成相机初始化、拍照识别流程(重量稳定 ≥10g 时触发) - PrepareCookActivity 新增 flCameraContainer(1dp 隐藏容器)用于相机预览绑定 - SelectDishActivity 临时注释 judgeDeviceConfig 逻辑,直接调用 block() - 修正 GpioUtils/L/LightManager 包名为 com.shuwei.dish.match.utils
This commit is contained in:
@@ -41,6 +41,7 @@ class GoodsInfoSearchAdapter(private var list: MutableList<CookFoodGoodsEntity>)
|
||||
): VH {
|
||||
val binding =
|
||||
ListItemSearchGoodsInfoBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
|
||||
return VH(binding)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.shuwei.dish.match.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.shuwei.dish.match.R
|
||||
import com.shuwei.dish.match.adapter.GoodsInfoSearchAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.databinding.DialogFoodRecognizeBinding
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
|
||||
/**
|
||||
* 菜品识别结果弹窗,继承 BottomSheetDialog 确保只初始化一次
|
||||
* @param activity 宿主 Activity
|
||||
* @param onItemSelected 用户点击某一菜品时的回调
|
||||
*/
|
||||
class FoodRecognizeDialog(
|
||||
private val activity: BaseActivity,
|
||||
private val onItemSelected: (item: CookFoodGoodsEntity) -> Unit
|
||||
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
||||
|
||||
private val binding = DialogFoodRecognizeBinding.inflate(LayoutInflater.from(activity))
|
||||
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||
private val adapter = GoodsInfoSearchAdapter(list).apply {
|
||||
setOnItemClickListener { _, _, position ->
|
||||
list[position].isClicked = true
|
||||
notifyItemChanged(position)
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
onItemSelected(list[position])
|
||||
dismiss()
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
setContentView(binding.root)
|
||||
setCancelable(true)
|
||||
behavior.skipCollapsed = false
|
||||
setOnDismissListener { activity.hideStatusBar() }
|
||||
binding.recyclerView.run {
|
||||
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
|
||||
adapter = this@FoodRecognizeDialog.adapter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载识别结果数据并显示弹窗
|
||||
* @param items 识别到的菜品列表
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun loadData(items: List<CookFoodGoodsEntity>) {
|
||||
list.clear()
|
||||
list.addAll(items)
|
||||
adapter.notifyDataSetChanged()
|
||||
if (!isShowing) show()
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.shuwei.dish.match.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.viewModels
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.shuwei.dish.match.R
|
||||
@@ -12,23 +13,34 @@ import com.shuwei.dish.match.adapter.DishPartAdapter
|
||||
import com.shuwei.dish.match.base.BaseActivity
|
||||
import com.shuwei.dish.match.databinding.ActivityPrepareCookBinding
|
||||
import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
|
||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||
import com.shuwei.dish.match.dialog.CommonDialog
|
||||
import com.shuwei.dish.match.dialog.FoodRecognizeDialog
|
||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||
import com.shuwei.dish.match.entity.FoodRecord
|
||||
import com.shuwei.dish.match.net.NetViewModel
|
||||
import android.view.ViewGroup
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding
|
||||
import com.shuwei.dish.match.objbox.FoodModule
|
||||
import com.shuwei.dish.match.utils.AddressUtil
|
||||
import com.shuwei.dish.match.utils.CameraUtils
|
||||
import com.shuwei.dish.match.utils.ImageUtil
|
||||
import com.shuwei.dish.match.utils.SwipeCallback
|
||||
import com.shuwei.dish.match.utils.WeightUtil
|
||||
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
||||
import com.shuwei.dish.match.utils.ext.gone
|
||||
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||
import com.shuwei.dish.match.utils.ext.startActivity
|
||||
import com.shuwei.dish.match.utils.ext.toJsonString
|
||||
import com.shuwei.dish.match.utils.ext.toast
|
||||
import com.shuwei.dish.match.utils.ext.visible
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.Serializable
|
||||
import kotlin.getValue
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
class PrepareCookActivity : BaseActivity() {
|
||||
@@ -40,6 +52,8 @@ class PrepareCookActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityPrepareCookBinding
|
||||
|
||||
private val cameraUtils: CameraUtils by lazy { CameraUtils(this) }
|
||||
|
||||
private var food: FoodRecord? = null
|
||||
|
||||
private var goodsList: MutableList<CookFoodGoodsEntity>? = null
|
||||
@@ -69,6 +83,7 @@ class PrepareCookActivity : BaseActivity() {
|
||||
binding.tvDishName.text = food?.foodName ?: ""
|
||||
addViewClickListener()
|
||||
|
||||
initCamera(binding.flCameraContainer)
|
||||
initRecyclerView()
|
||||
|
||||
getDishDetail()
|
||||
@@ -81,6 +96,9 @@ class PrepareCookActivity : BaseActivity() {
|
||||
//Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
|
||||
if (address == AddressUtil.ONE) {
|
||||
binding.tvDishPartWeight.text = "${weight}"
|
||||
if (state == WeightUtil.STATE_STABLE) {
|
||||
recognizeFood(weight)
|
||||
}
|
||||
}
|
||||
})
|
||||
binding.ivWeightClear.setOnClickListener {
|
||||
@@ -134,6 +152,25 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val isTakingPhoto = AtomicBoolean(false)
|
||||
|
||||
/**
|
||||
* 重量稳定时触发菜品识别
|
||||
* @param weight 当前稳定重量
|
||||
*/
|
||||
private fun recognizeFood(weight: Double) {
|
||||
if (weight < 10) {
|
||||
if (recognizeDialog.isShowing) recognizeDialog.dismiss()
|
||||
return
|
||||
}
|
||||
if (isTakingPhoto.get() || recognizeDialog.isShowing) return
|
||||
isTakingPhoto.set(true)
|
||||
cameraUtils.takePhoto(
|
||||
succCallback = cameraSuccessCallback,
|
||||
failCallback = cameraFailureCallback
|
||||
)
|
||||
}
|
||||
|
||||
private fun addFood() {
|
||||
FoodSearchDialog().show(this) { item ->
|
||||
val filterResult = list.firstOrNull { it.goodsId == item.goodsId }
|
||||
@@ -251,6 +288,16 @@ class PrepareCookActivity : BaseActivity() {
|
||||
|
||||
private var firstReqSize = 0
|
||||
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||
private val recognizeDialog by lazy {
|
||||
FoodRecognizeDialog(this) { item ->
|
||||
// TODO: 处理识别结果选中
|
||||
}
|
||||
.apply {
|
||||
setOnDismissListener {
|
||||
isTakingPhoto.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val dishPartAdapter by lazy {
|
||||
DishPartAdapter(list).apply {
|
||||
setOnItemClickListener { _, _, positon ->
|
||||
@@ -326,6 +373,26 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
cameraUtils.bind()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
cameraUtils.unbind()
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化相机并绑定预览容器
|
||||
* @param container 相机预览容器
|
||||
*/
|
||||
fun initCamera(container: ViewGroup) {
|
||||
cameraUtils.initCamera()
|
||||
val previewBinding = LayoutCameraPreviewBinding.inflate(layoutInflater, container)
|
||||
cameraUtils.setPreviewController(previewBinding.previewView)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("GestureBackNavigation")
|
||||
@Deprecated("Deprecated in Java")
|
||||
@@ -367,4 +434,49 @@ class PrepareCookActivity : BaseActivity() {
|
||||
}.show()
|
||||
}
|
||||
|
||||
private val cameraSuccessCallback: (Uri) -> Unit = { uri ->
|
||||
Log.d(TAG, "takePhoto success")
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val bitmap = ImageUtil.uriToBitmap(this@PrepareCookActivity, uri)
|
||||
if (bitmap == null) {
|
||||
Log.d(TAG, "takePhoto bitmap is null")
|
||||
isTakingPhoto.set(false)
|
||||
return@withContext
|
||||
}
|
||||
val foodScoreList = FoodModule.getFoodScoreList(bitmap)
|
||||
if (foodScoreList.isEmpty()) {
|
||||
Log.d(TAG, "takePhoto foodScoreList is empty")
|
||||
isTakingPhoto.set(false)
|
||||
return@withContext
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
queryFood(foodScoreList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val cameraFailureCallback: (String) -> Unit = { errMsg ->
|
||||
Log.d(TAG, "takePhoto failure")
|
||||
isTakingPhoto.set(false)
|
||||
}
|
||||
|
||||
private fun queryFood(list: List<FoodModule.IdNameScore>) {
|
||||
Log.d(TAG, "takePhoto queryFood, list=${list.toString()}")
|
||||
//调用接口成功,返回食材列表设置isTakingPhoto.set(false),暂时写死数据
|
||||
val foodList = mutableListOf<CookFoodGoodsEntity>()
|
||||
list.forEachIndexed { index, food ->
|
||||
val foodName = food.name.split("WP").first()
|
||||
val foodScore = ((1-food.score) * 100).roundedDecimalPlace(2)
|
||||
foodList.add(CookFoodGoodsEntity(
|
||||
goodsId = index.toString(),
|
||||
goodsName = "${foodName}-${foodScore}%",
|
||||
foodId = index.toString()
|
||||
))
|
||||
}
|
||||
recognizeDialog.loadData(foodList)
|
||||
isTakingPhoto.set(false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,18 +82,19 @@ class SelectDishActivity : BaseActivity() {
|
||||
private var configFinished = false
|
||||
|
||||
fun judgeDeviceConfig(block: () -> Unit) {
|
||||
if (configFinished) {
|
||||
// if (configFinished) {
|
||||
// block()
|
||||
// return
|
||||
// }
|
||||
// appViewModel.loadSeasoning {
|
||||
// if (it.isEmpty()) {
|
||||
// showDeviceConfigDialog()
|
||||
// return@loadSeasoning
|
||||
// }
|
||||
// configFinished = true
|
||||
// block()
|
||||
// }
|
||||
block()
|
||||
return
|
||||
}
|
||||
appViewModel.loadSeasoning {
|
||||
if (it.isEmpty()) {
|
||||
showDeviceConfigDialog()
|
||||
return@loadSeasoning
|
||||
}
|
||||
configFinished = true
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDeviceConfigDialog() {
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
package com.shuwei.dish.match.utils;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Administrator on 2018/11/9.
|
||||
*/
|
||||
public class GpioUtils {
|
||||
|
||||
private static final String TAG = "GpioUtils";
|
||||
|
||||
/*
|
||||
给export申请权限
|
||||
*/
|
||||
public static void upgradeRootPermissionForExport() {
|
||||
upgradeRootPermission("/sys/class/gpio/export");
|
||||
}
|
||||
|
||||
/*
|
||||
配置一个gpio路径
|
||||
*/
|
||||
public static boolean exportGpio(int gpio) {
|
||||
return writeNode("/sys/class/gpio/export", "" + gpio);
|
||||
}
|
||||
|
||||
/*
|
||||
给获取io口的状态的路径申请权限,该方法需要在exportGpio后调用
|
||||
*/
|
||||
public static void upgradeRootPermissionForGpio(int gpio) {
|
||||
upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/direction");
|
||||
upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/value");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
设置io口为输入或输出
|
||||
*/
|
||||
public static boolean setGpioDirection(int gpio, int arg) {
|
||||
String gpioDirection = "";
|
||||
if (arg == 0) gpioDirection = "out";
|
||||
else if (arg == 1) gpioDirection = "in";
|
||||
else return false;
|
||||
return writeNode("/sys/class/gpio/gpio" + gpio + "/direction", gpioDirection);
|
||||
}
|
||||
|
||||
/*
|
||||
获取io口的状态为输出还是输入
|
||||
*/
|
||||
public static String getGpioDirection(int gpio) {
|
||||
String gpioDirection = "";
|
||||
gpioDirection = readNode("/sys/class/gpio/gpio" + gpio + "/direction");
|
||||
return gpioDirection;
|
||||
}
|
||||
|
||||
/*
|
||||
给输出io口写值,高电平或低电平
|
||||
*/
|
||||
public static boolean writeGpioValue(int gpio, String arg) {
|
||||
return writeNode("/sys/class/gpio/gpio" + gpio + "/value", arg);
|
||||
}
|
||||
|
||||
//获取当前gpio是高还是低
|
||||
public static String getGpioValue(int gpio) {
|
||||
return readNode("/sys/class/gpio/gpio" + gpio + "/value");
|
||||
}
|
||||
|
||||
|
||||
private static boolean upgradeRootPermission(String path) {
|
||||
Process process = null;
|
||||
DataOutputStream os = null;
|
||||
try {
|
||||
String cmd = "chmod 777 " + path;
|
||||
process = Runtime.getRuntime().exec("su"); //切换到root帐号
|
||||
os = new DataOutputStream(process.getOutputStream());
|
||||
os.writeBytes(cmd + "\n");
|
||||
os.writeBytes("exit\n");
|
||||
os.flush();
|
||||
process.waitFor();
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
try {
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
process.destroy();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
return process.waitFor() == 0;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean writeNode(String path, String arg) {
|
||||
Log.d(TAG, "Gpio_test set node path: " + path + " arg: " + arg);
|
||||
if (path == null || arg == null) {
|
||||
Log.e(TAG, "set node error");
|
||||
return false;
|
||||
}
|
||||
FileWriter fileWriter = null;
|
||||
BufferedWriter bufferedWriter = null;
|
||||
try {
|
||||
fileWriter = new FileWriter(path);
|
||||
fileWriter.write(arg);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Gpio_test write node error!! path" + path + " arg: " + arg);
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (fileWriter != null) {
|
||||
fileWriter.close();
|
||||
}
|
||||
if (bufferedWriter != null) {
|
||||
bufferedWriter.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static long mTime = 0;
|
||||
private static int mFailTimes = 0;
|
||||
|
||||
private static String readNode(String path) {
|
||||
String result = "";
|
||||
|
||||
FileReader fread = null;
|
||||
BufferedReader buffer = null;
|
||||
try {
|
||||
fread = new FileReader(path);
|
||||
buffer = new BufferedReader(fread);
|
||||
String str = null;
|
||||
while ((str = buffer.readLine()) != null) {
|
||||
result = str;
|
||||
break;
|
||||
}
|
||||
mFailTimes = 0;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "IO Exception");
|
||||
e.printStackTrace();
|
||||
if (mTime == 0 || SystemClock.uptimeMillis() - mTime < 1000) {
|
||||
mFailTimes++;
|
||||
}
|
||||
if (mFailTimes >= 3) {
|
||||
Log.d(TAG, "read format node continuous failed three times, exist thread");
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (buffer != null) {
|
||||
buffer.close();
|
||||
}
|
||||
if (fread != null) {
|
||||
fread.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.shuwei.dish.match.utils;
|
||||
|
||||
/**
|
||||
* Log统一管理类
|
||||
*/
|
||||
public class L {
|
||||
|
||||
private L() {
|
||||
/* cannot be instantiated */
|
||||
throw new UnsupportedOperationException("cannot be instantiated");
|
||||
}
|
||||
|
||||
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||
private static final String TAG = "mzf";
|
||||
|
||||
// 下面四个是默认tag的函数
|
||||
public static void i(String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.i(TAG, msg);
|
||||
}
|
||||
|
||||
public static void d(String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.d(TAG, msg);
|
||||
}
|
||||
|
||||
public static void e(String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.e(TAG, msg);
|
||||
}
|
||||
|
||||
public static void v(String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.v(TAG, msg);
|
||||
}
|
||||
|
||||
// 下面是传入自定义tag的函数
|
||||
public static void i(String tag, String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.i(tag, msg);
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.d(tag, msg);
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.e(tag, msg);
|
||||
}
|
||||
|
||||
public static void v(String tag, String msg) {
|
||||
if (isDebug)
|
||||
android.util.Log.v(tag, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.shuwei.dish.match.utils;
|
||||
|
||||
public class LightManager {
|
||||
private static final String TAG = "LightManager";
|
||||
|
||||
public static void openGreenLight() {
|
||||
L.e(TAG, "openGreenLight");
|
||||
GpioUtils.writeGpioValue(41, "1");
|
||||
}
|
||||
|
||||
public static void closeGreenLight() {
|
||||
L.e(TAG, "closeGreenLight");
|
||||
GpioUtils.writeGpioValue(41, "0");
|
||||
}
|
||||
|
||||
public static void openRedLight() {
|
||||
L.e(TAG, "openRedLight");
|
||||
GpioUtils.writeGpioValue(40, "1");
|
||||
}
|
||||
|
||||
public static void closeRedLight() {
|
||||
L.e(TAG, "closeRedLight");
|
||||
GpioUtils.writeGpioValue(40, "0");
|
||||
}
|
||||
}
|
||||
@@ -262,6 +262,11 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/flCameraContainer"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btnCook"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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"
|
||||
android:orientation="vertical"
|
||||
tools:background="@color/white">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewLine"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:background="@drawable/shape_gray_dc_5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSheetName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="50dp"
|
||||
android:text="菜品识别结果"
|
||||
android:textColor="@color/black333"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="45dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginEnd="45dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:minHeight="500dp"
|
||||
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" />
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user