开发者问题收集

Jetpack Compose - 布局可重复使用的组件

2022-11-02
779

为了练习使用 Jetpack Compose 中的可重用组件,我开始了一个小练习。 见下图。

在此处输入图片说明

我想象绿色行、输入行和它们之间的行具有相同的结构。 第一个元素获得可用空间,第二个元素占用 50.dp,最后一个元素占用 70.dp。 我尝试将宽度分成变量,并将这些变量作为修饰符传递给行中的单个元素。我认为如果我需要额外的字段,我可以毫无问题地扩展它。

代码不起作用!

@Composable
fun groundComponent(
    modifier: Modifier = Modifier,
    spaceBetween: Dp = 0.dp,
    color: Color,
    content: @Composable () -> Unit
) {
    Surface(
        color = color
    ) {
        Row(
            modifier = modifier,
            horizontalArrangement = Arrangement.spacedBy(spaceBetween)
        ) {
            content()
        }
    }
}

@Composable
fun inputSection() {
val firstRowWidth = 1F
val secondRowWidth = 70.dp
val thirdRowWidth = 50.dp

Text("Add Ingredient")
groundComponent(color = Color.Green){
            Text( text="Ingredient", modifier = Modifier.weight(firstRowWidth ))
            Text( text="Amount", modifier = Modifier.widthIn(secondRowWidth ))
            Text( text="Unit", modifier = Modifier.widthIn(thirdRowWidth ))
        }
groundComponent{
            Text( text="Sugar", modifier = Modifier.weight(firstRowWidth ))
            Text( text="500", modifier = Modifier.widthIn(secondRowWidth ))
            Text( text="gr", modifier = Modifier.widthIn(thirdRowWidth ))
        }
groundComponent{
            Text( text="Carrot", modifier = Modifier.weight(firstRowWidth ))
            Text( text="1.5", modifier = Modifier.widthIn(secondRowWidth ))
            Text( text="kg", modifier = Modifier.widthIn(thirdRowWidth ))
        }
groundComponent{
                TextField(
value = "newIngredient", 
onValueChange = {}, 
modifier = Modifier.weight(firstRowWidth ))
            TextField(
value = "newAmount", 
onValueChange = {}, 
modifier = Modifier.widthIn(secondRowWidth )
)
            TextField(
value = "newUnit", 
onValueChange = {}, 
modifier = Modifier.widthIn(thirdRowWidth )
)
        }
Button(onClick={}){Text("add")}
}

我在使用 .weight 修饰符时遇到了几个错误。 那么解决这种情况的正确方法是什么呢?

谢谢!

2个回答

Modifier.weight 是在特定范围(例如 RowScope 和 ColumnScope)中定义的修饰符。要使用在特定范围中定义的修饰符,您需要将 Receiver 添加到内容中。BoxScope 定义为 Modifier.align(),例如,您也可以定义您的范围。

@Composable
fun GroundComponent(
    modifier: Modifier = Modifier,
    spaceBetween: Dp = 0.dp,
    color: Color=Color.Unspecified,
    content: @Composable RowScope.() -> Unit
) {
    Surface(
        color = color
    ) {

        // Can't call content here because it has RowScope as receiver
//        content()
        Row(
            modifier = modifier,
            horizontalArrangement = Arrangement.spacedBy(spaceBetween)
        ) {
            content()
        }
    }
}

此外,在 InputSection 中,您将权重分数定义为

val firstRowWidth = 1F
val secondRowWidth = 70.dp
val thirdRowWidth = 50.dp

这些值应该彼此成比例

例如,如果您设置 1/5/6。或者在 0f-1f 之间

并且按照惯例,您可以使用大写首字母命名 Composable,因为它们被视为小部件。

Thracian
2022-11-02

感谢您的回复和相当不错的解释! 在您的帮助下,我以这种方式解决了我的问题。

@Composable
fun InputRowGroundComponent(
    modifier: Modifier = Modifier,
    spaceBetweenElements: Dp = 0.dp,
    color: Color,
    content: @Composable RowScope.() -> Unit
) {
    Surface(
        color = color
    ) {
        Row(
            modifier = modifier,
            horizontalArrangement = Arrangement.spacedBy(spaceBetweenElements),
            verticalAlignment = Alignment.CenterVertically
        ) {
            content()
        }
    }
}

@Composable
fun OverviewHeader(
    modifier: Modifier = Modifier,
    text: String
) {
    Text(
        modifier = modifier,
        text = text,
        maxLines = 1,
        overflow = TextOverflow.Ellipsis,
        textAlign = TextAlign.Center
    )
}

@Composable
fun OverviewContent(
    modifier: Modifier = Modifier,
    text: String
) {
    Text(
        modifier = modifier,
        text = text,
        maxLines = 2,
        overflow = TextOverflow.Ellipsis,
    )
}

@Preview(showBackground = true, widthDp = 460)
@Composable
fun testPrev() {
    val rowWeights = listOf(6F,3F,2F)
    val rowSpacing = 8.dp
    val indentation = 10.dp
    Column(
        modifier = Modifier.padding(8.dp),
        verticalArrangement = Arrangement.spacedBy(rowSpacing)
    ) {
        InputRowGroundComponent(
            modifier = Modifier.heightIn(45.dp),
            spaceBetweenElements = rowSpacing,
            color = Color.Green
        ) {
            OverviewHeader(text = "Ingredient", modifier = Modifier.weight(rowWeights[0]))
            OverviewHeader(text = "Amount", modifier = Modifier.weight(rowWeights[1]))
            OverviewHeader(text = "Unit", modifier = Modifier.weight(rowWeights[2]))
        }
        InputRowGroundComponent(
            modifier = Modifier.heightIn(30.dp),
            spaceBetweenElements = rowSpacing,
            color = Color.Unspecified
        ) {
            OverviewContent(text = "Sugar", modifier = Modifier.weight(rowWeights[0]).padding(start=indentation))
            OverviewContent(text = "500", modifier = Modifier.weight(rowWeights[1]).padding(start=indentation))
            OverviewContent(text = "gr", modifier = Modifier.weight(rowWeights[2]).padding(start=indentation))
        }
        InputRowGroundComponent(
            modifier = Modifier.heightIn(30.dp),
            spaceBetweenElements = rowSpacing,
            color = Color.Unspecified
        ) {
            OverviewContent(text = "Carrot", modifier = Modifier.weight(rowWeights[0]).padding(start=indentation))
            OverviewContent(text = "1.5", modifier = Modifier.weight(rowWeights[1]).padding(start=indentation))
            OverviewContent(text = "kg", modifier = Modifier.weight(rowWeights[2]).padding(start=indentation))
        }
        InputRowGroundComponent(
            spaceBetweenElements = rowSpacing,
            color = Color.Unspecified
        ) {
            TextField(value = "", onValueChange = {}, modifier = Modifier.weight(rowWeights[0]))
            TextField(value = "", onValueChange = {}, modifier = Modifier.weight(rowWeights[1]))
            TextField(value = "", onValueChange = {}, modifier = Modifier.weight(rowWeights[2]))
        }
        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = { /*Todo*/ },
            content = {
                Row(
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Icon(
                        imageVector = Icons.Filled.Add,
                        contentDescription = "Add Ingredient"
                    )
                    Text(
                        text = "Add"
                    )
                }
            }
        )
    }
}

这种方法现在正确吗?

Pferdesalbe
2022-11-06