如何在Jetpack Compose中的动态按钮上显示加载器

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

How to show loader on a dynamic button in jetpack compose

问题

以下是您要翻译的内容:

"So the issue I'm facing is I have a button which can have dynamic text, button have a state isLoading which when turned true, View is recomposed to show loader. Now Loader have its own width & height. How do I manage the loader to follow the same dimensions as of the text which was shown earlier. Right now when loader appears the button size grow large & after the loading is complete & isLoading is false again, the button would come to its actually size with text inside it.

Edit 1:
The approach suggested by @thracian is working fine, other than a weird issue where the button gets some predefined height (& so resulting in same value while calculating the view height), which makes the button looks taller than what I'm planning to implement. Attaching code for ref, how do I make this button follow wrapped content & at the same time get the same calculated value in view size as well."

请注意,代码部分不会被翻译,只翻译文本内容。

英文:

So the issue I'm facing is I have a button which can have dynamic text, button have a state isLoading which when turned true, View is recomposed to show loader. Now Loader have its own width & height. How do I manage the loader to follow the same dimensions as of the text which was shown earlier. Right now when loader appears the button size grow large & after the loading is complete & isLoading is false again, the button would come to its actually size with text inside it.

Edit 1:
The approach suggested by @thracian is working fine, other than a weird issue where the button gets some predefined height (& so resulting in same value while calculating the view height), which makes the button looks taller than what I'm planning to implement. Attaching code for ref, how do I make this button follow wrapped content & at the same time get the same calculated value in view size as well.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-kotlin -->

@Composable
fun GreenCTA(
    modifier: Modifier = Modifier, onClick: () -&gt; Unit, title: String, isShowLoader: Boolean
) {
    var buttonSize by remember {
        mutableStateOf(DpSize.Zero)
    }
    val density = LocalDensity.current
    Button(
        modifier = modifier
            .then(if (buttonSize != DpSize.Zero) modifier.size(buttonSize) else modifier)
            .onSizeChanged { newSize -&gt;
                if (buttonSize == DpSize.Zero) {
                    buttonSize = with(density) {
                        newSize
                            .toSize()
                            .toDpSize()
                    }
                }
            },
        onClick = { onClick.invoke() },
        border = BorderStroke(1.dp, color = colorResource(id = R.color.pass_color_c2e6cd)),
        colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(id = R.color.pass_color_e3f6ec)),
        shape = RoundedCornerShape(6.dp),
        contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
        elevation = ButtonDefaults.elevation(0.dp),
    ) {
        if (isShowLoader) BlueLoader(
            modifier = Modifier
                .fillMaxHeight()
                .aspectRatio(3f)
        )
        else {
            Row(
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                Image(
                    painter = painterResource(id = R.drawable.ic_add_tag),
                    contentDescription = &quot;Button Logo&quot;
                )
                Text(
                    text = title,
                    style = MaterialTheme.typography.body2.copy(lineHeight = 20.sp),
                    fontWeight = FontWeight.SemiBold,
                )
            }
        }
    }
}

<!-- end snippet -->

答案1

得分: 1

以下是您要翻译的内容:

如果您希望根据最初组成的文本来调整按钮的大小,您可以在显示文本时使用 Modifier.onSizeChanged 来获取按钮的尺寸,然后在文本不在组合中时将这些尺寸设置为按钮的大小,如下所示:

Preview
@Composable
private fun Test() {

    var isLoading by remember { mutableStateOf(false) }
    var buttonSize by remember { mutableStateOf(DpSize.Zero) }
    val density = LocalDensity.current

    OutlinedButton(
        modifier = Modifier
            .then(
                if (buttonSize != DpSize.Zero) Modifier.size(buttonSize) else Modifier
            )
            .onSizeChanged { newSize ->
                if (buttonSize == DpSize.Zero) {
                    buttonSize = with(density) {
                        newSize
                            .toSize()
                            .toDpSize()
                    }
                }
            },
        onClick = { isLoading = isLoading.not() }) {
        if (isLoading) {
            CircularProgressIndicator(
                modifier = Modifier
                    .fillMaxHeight()
                    .aspectRatio(1f)
            )
        } else {
            Text(text = "Click me")
        }
    }
}

此外,如果您希望调整按钮的大小以适应尚未组合的 Composable,例如加载器的大小,您可以使用 SubcomposeLayout 来提前获取尺寸,可以参考以下答案:

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

英文:

If you wish to adjust size of the button based on Text which is composed initially you can use Modifier.onSizeChanged for Button dimensions while Text is displayed and then set these dimensions as size to button while Text is out of Composition such as

Preview
@Composable
private fun Test() {

    var isLoading by remember { mutableStateOf(false) }
    var buttonSize by remember { mutableStateOf(DpSize.Zero) }
    val density = LocalDensity.current

    OutlinedButton(
        modifier = Modifier
            .then(
                if (buttonSize != DpSize.Zero) Modifier.size(buttonSize) else Modifier
            )
            .onSizeChanged { newSize -&gt;
                if (buttonSize == DpSize.Zero) {
                    buttonSize = with(density) {
                        newSize
                            .toSize()
                            .toDpSize()
                    }
                }
            },
        onClick = { isLoading = isLoading.not() }) {
        if (isLoading) {
            CircularProgressIndicator(
                modifier = Modifier
                    .fillMaxHeight()
                    .aspectRatio(1f)
            )
        } else {
            Text(text = &quot;Click me&quot;)
        }
    }
}

Also if you wish to adjust size of a Button to a Composable that is not composed yet, for instance loader size, you can use SubcomposeLayout to get dimensions beforehand as in this answer

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

答案2

得分: 0

以下是您要翻译的代码部分:

@Composable
fun ButtonWithLoader(
    buttonText: String,
    backgroundColor: Color,
    contentColor: Color = White,
    showLoader: Boolean = false,
    showBorder: Boolean,
    onClick: () -&gt; Unit,
) {
    if (showLoader) {
        Row(
            modifier = Modifier
                .widthIn(max = 600.dp)
                .fillMaxWidth()
                .padding(start = 20.dp, end = 20.dp, top = 20.dp)
                .height(48.dp)
                .motionClickEvent { onClick() }
                .border(
                    if (showBorder) 1.dp else 0.dp,
                    colors.textPrimary.copy(0.08f),
                    RoundedCornerShape(50.dp)
                )
                .background(backgroundColor, RoundedCornerShape(50.dp)),
            horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically
        ) {
            CircularProgressIndicator(color = colors.primary, modifier = Modifier.size(28.dp))
        }
    } else {
        Row(
            modifier = Modifier
                .widthIn(max = 600.dp)
                .fillMaxWidth()
                .padding(start = 20.dp, end = 20.dp, top = 20.dp)
                .height(48.dp)
                .motionClickEvent { onClick() } // motionClickEvent is my custom click modifier, use clickable modifier over here
                .border(
                    if (showBorder) 1.dp else 0.dp,
                    colors.textPrimary.copy(0.08f),
                    RoundedCornerShape(50.dp)
                )
                .background(backgroundColor, RoundedCornerShape(50.dp)),
            horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = buttonText,
                style = AppTheme.typography.buttonStyle,
                color = contentColor,
                modifier = Modifier.padding(horizontal = 12.dp)
            )
        }
    }
}

使用方法:

var isGoogleLoginInProgress by remember { mutableStateOf(false) }
ButtonWithLoader(
   buttonText = stringResource(R.string.sign_in_method_sign_in_with_google_btn_text),
   backgroundColor = White,
   contentColor = textColor.copy(0.87f),
   showBorder = true,
   showLoader = isGoogleLoginInProgress
) {
     isGoogleLoginInProgress = !isGoogleLoginInProgress // Replace this with your logic
}

示例输出:

如何在Jetpack Compose中的动态按钮上显示加载器

英文:

You can use below Custom-Composable for achieving your requirements:

@Composable
fun ButtonWithLoader(
    buttonText: String,
    backgroundColor: Color,
    contentColor: Color = White,
    showLoader: Boolean = false,
    showBorder: Boolean,
    onClick: () -&gt; Unit,
) {
    if (showLoader) {
        Row(
            modifier = Modifier
                .widthIn(max = 600.dp)
                .fillMaxWidth()
                .padding(start = 20.dp, end = 20.dp, top = 20.dp)
                .height(48.dp)
                .motionClickEvent { onClick() }
                .border(
                    if (showBorder) 1.dp else 0.dp,
                    colors.textPrimary.copy(0.08f),
                    RoundedCornerShape(50.dp)
                )
                .background(backgroundColor, RoundedCornerShape(50.dp)),
            horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically
        ) {
            CircularProgressIndicator(color = colors.primary, modifier = Modifier.size(28.dp))
        }
    } else {
        Row(
            modifier = Modifier
                .widthIn(max = 600.dp)
                .fillMaxWidth()
                .padding(start = 20.dp, end = 20.dp, top = 20.dp)
                .height(48.dp)
                .motionClickEvent { onClick() } // motionClickEvent is my custom click modifier, use clickable modifier over here
                .border(
                    if (showBorder) 1.dp else 0.dp,
                    colors.textPrimary.copy(0.08f),
                    RoundedCornerShape(50.dp)
                )
                .background(backgroundColor, RoundedCornerShape(50.dp)),
            horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = buttonText,
                style = AppTheme.typography.buttonStyle,
                color = contentColor,
                modifier = Modifier.padding(horizontal = 12.dp)
            )
        }
    }
}

Usage:

var isGoogleLoginInProgress by remember { mutableStateOf(false) }
ButtonWithLoader(
   buttonText = stringResource(R.string.sign_in_method_sign_in_with_google_btn_text),
   backgroundColor = White,
   contentColor = textColor.copy(0.87f),
   showBorder = true,
   showLoader = isGoogleLoginInProgress
) {
     isGoogleLoginInProgress = !isGoogleLoginInProgress // Replace this with your logic
}

Sample output:

如何在Jetpack Compose中的动态按钮上显示加载器

huangapple
  • 本文由 发表于 2023年6月13日 18:34:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76463998.html
匿名

发表评论

匿名网友

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

确定