英文:
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: () -> 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 ->
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 = "Button Logo"
)
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 来提前获取尺寸,可以参考以下答案:
英文:
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 ->
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")
}
}
}
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
答案2
得分: 0
以下是您要翻译的代码部分:
@Composable
fun ButtonWithLoader(
buttonText: String,
backgroundColor: Color,
contentColor: Color = White,
showLoader: Boolean = false,
showBorder: Boolean,
onClick: () -> 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
}
示例输出:
英文:
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: () -> 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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论