我构建了一个非常小的实践应用程序,但我发现了一些问题。
package com.example.jetrecept
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.sharp.Add
import androidx.compose.material.icons.sharp.Delete
import androidx.compose.material.icons.sharp.Edit
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.example.jetrecept.ui.theme.JetReceptTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetReceptTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
MainContent()
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun MainContent() {
var recipeTitle by remember { mutableStateOf("") }
val ingredientList = remember { mutableStateListOf<Ingredient>() }
var amount by remember { mutableStateOf("") } // Change to Double
var unit by remember { mutableStateOf("") }
var notation by remember { mutableStateOf("") }
RecipeContent(
recipeTitle = recipeTitle,
onRecipeTitleChange = { recipeTitle = it },
ingredientList = ingredientList,
onIngredientListUpdate = { ingredient: Ingredient, i: Int -> ingredientList[i] = ingredient},
onIngredientListAdd = { ingredientList.add(it) },
onIngredientListRemoveItem = { ingredientList.removeAt(it)},
amount = amount,
onAmountChange = { amount = it},
unit = unit,
onUnitChange = { unit = it},
notation = notation,
onNotationChange = { notation = it}
)
RecipeHeader(
recipeTitle = recipeTitle
)
}
@Composable
fun RecipeHeader(
recipeTitle: String
) {
//JetReciptTheme {
Column {
//Text(text="recipetitle: $recipeTitle") // Just for testing, if hoisting works
}
//}
}
@Composable
fun RecipeContent(
recipeTitle: String,
onRecipeTitleChange: (String) -> Unit,
ingredientList: MutableList<Ingredient>,
onIngredientListAdd: (Ingredient) -> Unit,
onIngredientListUpdate: (Ingredient, Int) -> Unit,
onIngredientListRemoveItem: (Int) -> Unit,
amount: String, // change to Double,
onAmountChange: (String) -> Unit, //change to (Double) -> Unit,
unit: String,
onUnitChange: (String) -> Unit,
notation: String,
onNotationChange: (String) -> Unit
) {
Column(modifier = Modifier
.fillMaxSize()
.padding(21.dp)) {
// Headline
Text(text="Add new recipe",
modifier = Modifier
.fillMaxWidth()
.padding(34.dp),
textAlign = TextAlign.Center)
// Title of recipe - input
SectionHeadline(title = "Recipename")
TextField(
value = recipeTitle,
onValueChange = { onRecipeTitleChange(it) },
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 34.dp),
// Keyboard Action fehlt noch
)
// Ingredient - section
SectionHeadline(title = "Ingredients")
// Writing headline over the Ingredient table
if (ingredientList.isNotEmpty()) {
IngredientDescription(
modifier = Modifier.padding(bottom=4.dp),
firstColumn = "Nr.",
secondColumn = "Amount",
thirdColumn = "Unit",
fourthColumn = "Notation"
)
Divider(modifier = Modifier
.height(10.dp)
.padding(bottom = 4.dp, top = 4.dp))
}
// Print all Ingredients to an Row
ingredientList.mapIndexed { index, ingredient -> IngredientRow(
id = index,
ingredient = ingredient,
onIngredientListUpdate = onIngredientListUpdate,
onIngredientListRemoveItem = onIngredientListRemoveItem,
amount = amount,
onAmountChange = onAmountChange,
unit = unit,
onUnitChange = onUnitChange,
notation = notation,
onNotationChange = onNotationChange
)
}
// Ingredient input row
Row {
TextField(
value = amount,
onValueChange = { onAmountChange(it)},
modifier = Modifier
.width(100.dp)
.padding(end = 8.dp),
label = { Text(text="amount") },
singleLine = true
)
TextField(
value = unit,
onValueChange = { onUnitChange(it)},
modifier = Modifier
.width(80.dp)
.padding(end = 8.dp),
label = { Text(text = "unit") },
singleLine = true
)
TextField(
value = notation,
onValueChange = { onNotationChange(it)},
modifier = Modifier.weight(1F),
label = { Text(text = "notation")},
singleLine = true
)
}
Spacer(modifier= Modifier.height(8.dp))
// Add - Button, adding Ingredients
IconButton(
buttonText = "add",
icon = Icons.Sharp.Add,
iconDescription = "add icon",
enabled = amount.isNotBlank() && unit.isNotBlank() && notation.isNotBlank(),
onClick = {
onIngredientListAdd(Ingredient(amount=amount, unit=unit, notation=notation))
onAmountChange(""); onUnitChange(""); onNotationChange("")
})
}
}
@Composable
fun IngredientRow(
id: Int = 1,
ingredient: Ingredient,
onIngredientListUpdate: (Ingredient, Int) -> Unit,
onIngredientListRemoveItem: (Int) -> Unit,
amount: String,
onAmountChange: (String) -> Unit,
unit: String,
onUnitChange: (String) -> Unit,
notation: String,
onNotationChange: (String) -> Unit
) {
var buttonVisibility by remember { mutableStateOf(false)}
var showEditDialog by remember { mutableStateOf(false)}
Column( modifier = Modifier.fillMaxWidth()) {
IngredientDescription(
modifier = Modifier.clickable { buttonVisibility = !buttonVisibility },
firstColumn = "$id",
secondColumn = ingredient.amount,
thirdColumn = ingredient.unit,
fourthColumn = ingredient.notation
)
if (buttonVisibility) {
Row(modifier = Modifier
.padding(bottom = 8.dp, top = 8.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
IconButton(
buttonText = "edit",
icon = Icons.Sharp.Edit,
iconDescription = "edit icon",
onClick = {
onAmountChange( ingredient.amount)
onUnitChange( ingredient.unit)
onNotationChange( ingredient.notation)
showEditDialog = true}
)
IconButton(
buttonText = "delete",
icon = Icons.Sharp.Delete,
iconDescription = "delete icon",
onClick = { onIngredientListRemoveItem(id) }
)
}
}
Divider(modifier = Modifier
.height(10.dp)
.padding(bottom = 4.dp, top = 4.dp))
if (showEditDialog) {
AlertDialog(
onDismissRequest = {
onAmountChange(""); onUnitChange(""); onNotationChange("")
showEditDialog = false},
title = {Text(text="Edit ingredient")},
text = {
Column {
Text(text="Amount:")
TextField(value = amount, onValueChange = { onAmountChange(it) })
Text(text="Unit:")
TextField(value = unit, onValueChange = { onUnitChange(it) })
Text(text="Notation:")
TextField(value = notation, onValueChange = { onNotationChange(it) })
}
},
confirmButton = { onIngredientListUpdate(
Ingredient(amount= amount, unit= unit, notation= notation), id)
Button(onClick = {
showEditDialog = false
buttonVisibility = false
onAmountChange(""); onUnitChange(""); onNotationChange("")}) {
Text(text = "apply")
}
},
dismissButton = {
Button(onClick = {
showEditDialog = false
buttonVisibility = false
onAmountChange(""); onUnitChange(""); onNotationChange("")}) {
Text(text = "discard")
}
}
)
}
}
}
@Composable
fun SectionHeadline(title: String) {
Text(text = title)
Divider(modifier = Modifier.height(2.dp))
Spacer(modifier = Modifier.height(8.dp))
}
@Composable
fun IngredientDescription(
modifier: Modifier = Modifier,
firstColumn: String, secondColumn: String, thirdColumn: String, fourthColumn:String) {
Row( modifier = modifier
.fillMaxWidth()
.padding(bottom = 4.dp, top = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(text = firstColumn, modifier = Modifier.width(30.dp), textAlign = TextAlign.Center)
Text(text = secondColumn, modifier = Modifier.width(60.dp), textAlign = TextAlign.Center)
Text(text = thirdColumn, modifier = Modifier.width(50.dp), textAlign = TextAlign.Center)
Text(text = fourthColumn, modifier = Modifier.weight(1F))
}
}
@Composable
fun IconButton(
buttonText: String,
icon: ImageVector,
enabled: Boolean = true,
iconDescription: String,
onClick: () -> Unit
) {
Button(onClick = onClick, enabled = enabled) {
Text(text=buttonText, modifier = Modifier.padding(end=5.dp))
Icon(imageVector = icon, contentDescription = iconDescription)
}
}
// data class Ingredient (var amount: Double, var unit: String, var notation: String)
data class Ingredient (var amount: String, var unit: String, var notation: String)
提升的方式是否正确?我的意思是,我将大部分状态从Composable中取出,但其中的一些状态只是用于内部工作。我是否也应该将其从Composable中取出,使其完全无状态(buttonVisibility
和showEditDialog
)?
有什么我可以做得更好的吗?
1条答案
按热度按时间9ceoxa921#
第一件事首先是需要关注点分离到您的代码。因此,在未来,如果需要修改,您可以轻松地修改它,而无需弄清楚每个组合函数是如何设计的,如何管理状态以及在哪里。为此,您可以遵循任何设计架构(优选的是经由模型-数据存储、视图-UI元素、视图模型-状态管理和逻辑工作-MVVM体系结构的单向数据流)
我知道你的应用程序是如此之小,但干净的设计在未来的帮助。