如何衡量可组合性?

net*_*men 7 android android-button android-jetpack-compose

我有一个可组合按钮,可以根据状态显示文本或加载程序

enum class State { NORMAL, LOADING }

@Composable
fun MyButton(onClick: () -> Unit, text: String, state: State) {
    Button(onClick, Modifier.height(60.dp)) {
        if (state == State.NORMAL) {
            Text(text, fontSize = 32.sp)
        } else {
            CircularProgressIndicator(color = Color.Yellow)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我这样使用它:

MyButton(
        onClick = {
            state = if (state == State.NORMAL) State.LOADING else State.NORMAL
        },
        "hello",
        state
)
Run Code Online (Sandbox Code Playgroud)

但进入状态时按钮会缩小loading。我如何在状态中测量它,以便稍后normal在状态中分配这个测量的宽度?loading

Gab*_*tti 11

假设正常状态出现在加载状态之前,您可以使用onGloballyPositioned修饰符获取 的大小Text并将其应用于CircularProgressIndicator.

就像是:

@Composable
fun MyButton(onClick: () -> Unit, text: String, state: State) {
    var sizeText by remember { mutableStateOf(IntSize.Zero) }

    Button(onClick, Modifier.height(60.dp)) {
        if (state == State.NORMAL) {
            Text(text, fontSize = 32.sp,
                modifier = Modifier.onGloballyPositioned {
                    sizeText = it.size
                })
        } else {
            Box(Modifier.size(with(LocalDensity.current){ (sizeText.width).toDp()},with(LocalDensity.current){ (sizeText.height).toDp()}),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator(color = Color.Yellow)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 我看到“onGloballyPositioned”回调被调用了大约 6 次。只是想知道使用它是否会对性能产生影响 (3认同)

Fra*_*esc 6

您可以使用自定义布局 - 当您从“加载”或“正常”开始时,这都有效:

@Composable
fun CustomContainer(
    modifier: Modifier = Modifier,
    state: State,
    content: @Composable () -> Unit,
) {
    Layout(
        modifier = modifier,
        content = content,
    ) { measurables, constraints ->
        check(measurables.size == 2) { "This composable requires 2 children" }
        val first = measurables[0]
        val second = measurables[1]
        val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
        val firstPlaceable = first.measure(looseConstraints)
        val secondPlaceable = second.measure(looseConstraints)
        val requiredWidth = max(firstPlaceable.width, secondPlaceable.width)
        val requiredHeight = max(firstPlaceable.height, secondPlaceable.height)
        layout(
            requiredWidth,
            requiredHeight
        ) {
            when (state) {
                State.LOADING -> {
                    firstPlaceable.place(
                        x = (requiredWidth - firstPlaceable.width) / 2,
                        y = (requiredHeight - firstPlaceable.height) / 2,
                    )
                }
                State.NORMAL -> {
                    secondPlaceable.place(
                        x = (requiredWidth - secondPlaceable.width) / 2,
                        y = (requiredHeight - secondPlaceable.height) / 2,
                    )
                }
            }
        }
    }
}

@Preview
@Composable
fun CustomButtonPreview() {
    SampleTheme {
        var state by remember {
            mutableStateOf(State.LOADING)
        }
        Button(
            onClick = {
                state = when (state) {
                    State.NORMAL -> State.LOADING
                    State.LOADING -> State.NORMAL
                }
            },
            Modifier.height(60.dp)
        ) {
            CustomContainer(state = state) {
                CircularProgressIndicator(color = Color.Yellow)
                Text("Text here", fontSize = 32.sp)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述