更改按钮文本而不更改按钮宽度?

huangapple go评论57阅读模式
英文:

Change button text without changing the button width?

问题

saveInProgress设置为true时,Button的文本变短,Button会重新调整大小。我想让Button保持原始大小(不设置固定大小)。我该如何做到这一点?

英文:

Consider the following code:

val saveInProgress = false // in reality might come from a ViewModel

Button(onClick = {}) {
	val text = if(saveInProgress) "Save" else "..."
	Text(text)
}

When saveInProgress is set to true, the Button text gets shorter and the Button resizes. I want the Button to keep it's original size though (without setting a fixed size). How can I do that?

答案1

得分: 2

你可以设置 Modifier.widthIn(),以确保按钮的最小宽度不小于指定的值。

例如:

val saveInProgress = false

Button(
    onClick = {},
    modifier = Modifier.widthIn(min = 80.dp)
) {
    val text = if (saveInProgress) "Save" else "..."
    Text(text)
}
英文:

You can set Modifier.widthIn(), so that the button's minimum width is not less than the specified value.

For example:

val saveInProgress = false

Button(
    onClick = {},
    modifier = Modifier.widthIn(min = 80.dp)
) {
    val text = if (saveInProgress) "Save" else "..."
    Text(text)
}

答案2

得分: 2

在 Jetpack 版本 1.4.x 中,引入了 rememberTextMeasurer 用于测量文本。通过测量文本,您可以在将任何内容布局在 Composable 中之前就获得宽度。

    val text = "Initial Text Size"
    val density = LocalDensity.current
    val textMeasurer: TextMeasurer = rememberTextMeasurer()

    val style: TextStyle = MaterialTheme.typography.button
    val initialWidthDp: Dp = remember(text) {
        with(density) {
            textMeasurer.measure(
                text = text,
                style= style,
            ).size.width.toDp()
        }
    }

按钮的样式是必需的,以正确测量文本。

@Preview
@Composable
private fun TextWidthSample() {

    val text = "Initial Text Size"
    val density = LocalDensity.current
    val textMeasurer: TextMeasurer = rememberTextMeasurer()

    val style: TextStyle = MaterialTheme.typography.button
    val initialWidthDp: Dp = remember(text) {
        with(density) {
            textMeasurer.measure(
                text = text,
                style = style,
            ).size.width.toDp()
        }
    }

    var isLoading by remember {
        mutableStateOf(false)
    }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(20.dp)
    ) {
        Button(
            onClick = { /*TODO*/ }
        ) {
            Text(
                modifier = Modifier
                    .width(initialWidthDp),
                text = if (isLoading) "Loading" else text,
                textAlign = TextAlign.Center
            )
        }

        Spacer(modifier = Modifier.height(20.dp))
        Button(
            onClick = { isLoading = isLoading.not() }
        ) {
            Text("Loading: $isLoading")
        }
    }
}

如果版本低于 1.4.0 并且不想使用实验性 API,可以使用 Modifier.onSizeChanged 与另一个重新组合或 SubcomposeLayout,而无需另一个重新组合。可以使用 SubcomposeLayout 来获取 Composable 的尺寸,即使在测量和布局之前,也可以像在 Button 内添加进度按钮一样进行操作。

https://stackoverflow.com/questions/73705519/how-to-adjust-size-of-component-to-its-child-and-remain-unchanged-when-its-chi

英文:

In Jetpack Version 1.4.x rememberTextMeasurer is introduced to measure text. By measuring your text you can get width even before laying outt anything in a Composable as

val text = "Initial Text Size"
val density = LocalDensity.current
val textMeasurer: TextMeasurer = rememberTextMeasurer()

val style: TextStyle = MaterialTheme.typography.button
val initialWidthDp: Dp = remember(text) {
    with(density) {
        textMeasurer.measure(
            text = text,
            style= style,
        ).size.width.toDp()
    }
}

Style of button is required to measure text correctly.

更改按钮文本而不更改按钮宽度?

Full sample

@Preview
@Composable
private fun TextWidthSample() {

    val text = "Initial Text Size"
    val density = LocalDensity.current
    val textMeasurer: TextMeasurer = rememberTextMeasurer()

    val style: TextStyle = MaterialTheme.typography.button
    val initialWidthDp: Dp = remember(text) {
        with(density) {
            textMeasurer.measure(
                text = text,
                style = style,
            ).size.width.toDp()
        }
    }

    var isLoading by remember {
        mutableStateOf(false)
    }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(20.dp)
    ) {
        Button(
            onClick = { /*TODO*/ }
        ) {
            Text(
                modifier = Modifier
                    .width(initialWidthDp),
                text = if (isLoading) "Loading" else text,
                textAlign = TextAlign.Center
            )
        }

        Spacer(modifier = Modifier.height(20.dp))
        Button(
            onClick = { isLoading = isLoading.not() }
        ) {
            Text("Loading: $isLoading")
        }
    }
}

If version is lower than 1.4.0 and don't want to use experimental api you can use Modifier.onSizeChanged with another recomposition or SubcomposeLayout without another recomposition. SubcomposeLayout can be used to get dimensions of Composable even before it's measured and laid out like adding progress button inside Button while loading.

https://stackoverflow.com/questions/73705519/how-to-adjust-size-of-component-to-its-child-and-remain-unchanged-when-its-chi

答案3

得分: 1

以下是翻译的内容:

var maxWidth by remember { mutableStateOf(0) }
Button(
    modifier = Modifier
        .onSizeChanged { maxWidth = maxOf(maxWidth, it.width) }
        .then(if (maxWidth > 0) Modifier.width(maxWidth) else Modifier)
) {}
fun Modifier.invisible(isInvisible: Boolean) = drawWithContent {
  if (!isInvisible) {
    drawContent()
  }
}

Button {
    Box {
        Text("保存", Modifier.invisible(saveInProgress))
        Text("...", Modifier.invisible(!saveInProgress))
    }
}
英文:

There are multiple solutions to this, you can for example use Modifier.onSizeChanged on the Button to keep track of max width and then apply that width. This will make sure that the Button never becomes smaller. Something like this:

var maxWidth by remember { mutableStateOf(0) }
Button(
    modifier = Modifier
        .onSizeChanged { maxWidth = maxOf(maxWidth, it.width) }
        .then(if (maxWidth > 0) Modifier.width(maxWidth) else Modifier)
) {}

But this is not ideal if your second text is gonna be longer, so maybe better solution is to put both texts inside the button and make one of them invisible, like this:

fun Modifier.invisible(isInvisible: Boolean) = drawWithContent {
  if (!isInvisible) {
    drawContent()
  }
}

Button {
    Box {
        Text("Save", Modifier.invisible(saveInProgress))
        Text("...", Modifier.invisible(!saveInProgress))
    }
}

huangapple
  • 本文由 发表于 2023年4月17日 03:21:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76029898.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定