英文:
How to animate a circular background color for a `Composable`?
问题
Here's the translated code portion:
@Composable
fun PulsatingCircle(content: @Composable () -> Unit) {
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 2f, // 2 to see if it does really something quickly
animationSpec = infiniteRepeatable(
animation = tween(1700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
modifier = Modifier
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val currentHeight = placeable.height
val currentWidth = placeable.width
val newDiameter = maxOf(currentHeight, currentWidth)
val newScale = newDiameter * scale
layout(newScale.toInt(), newScale.toInt()) {
placeable.placeRelative(
((newScale - currentWidth) / 2).toInt(),
((newScale - currentHeight) / 2).toInt()
)
}
}
.background(color = Color.Red, shape = CircleShape)
) {
content()
}
}
Please note that I've translated the code portion only, as per your request. If you have any specific questions or need further assistance with this code, feel free to ask.
英文:
My goal is to have a Composable
fun (or Modifier
extension) which I can call from another Composable
method which will add a circular red background to it. The background should grow and shrink slowly by 10%.
The red background does not animate and I would like to know what is wrong with my code. The content itself should remain the same, the red background should only grow and shrink:
@Composable
fun PulsatingCircle(content: @Composable () -> Unit) {
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 2f, // 2 to see if it does really something quickly
animationSpec = infiniteRepeatable(
animation = tween(1700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
modifier = Modifier
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val currentHeight = placeable.height
val currentWidth = placeable.width
val newDiameter = maxOf(currentHeight, currentWidth)
val newScale = newDiameter * scale
layout(newScale.toInt(), newScale.toInt()) {
placeable.placeRelative(
((newScale - currentWidth) / 2).toInt(),
((newScale - currentHeight) / 2).toInt()
)
}
}
.background(color = Color.Red, shape = CircleShape)
) {
content()
}
}
答案1
得分: 2
如果在更改大小的同时使用 Layout 移动同级元素的目的是使用 Modifier.drawBehind{} 在 Modifier.layout 之前,但这可以很容易地通过动画实现 Modifier.drawBehind{drawCircle(Color.Red, radius = size*scale)}
使用 Layout 时,您还可以使用 Offset,以便在父级具有品红边框并增长时,内容不会移动。
对于 Modifier.drawBehind{},您可以创建一个函数 animateBackground
,并在其内部使用 drawBehind
绘制动画背景。
演示代码中,通过 PulsatingCircle
和 PulsatingCircle2
函数以及 animateBackground
函数,展示了动画效果和不同布局的使用。
英文:
If the purpose of using Layout to move siblings while changing size Modifier.background() should be before Modifier.layout but this can be easily animated Modifier.drawBehind{drawCircle(Color.Red, radius = size*scale)}
With Layout you can use Offset too If you don't want content to move while parent with Magenta border is growing as
@Composable
fun PulsatingCircle(content: @Composable () -> Unit) {
val infiniteTransition = rememberInfiniteTransition(label = "")
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 2f, // 2 to see if it does really something quickly
animationSpec = infiniteRepeatable(
animation = tween(1700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
), label = ""
)
Box(
modifier = Modifier
.border(1.dp, Color.Magenta)
.background(color = Color.Red, shape = CircleShape)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val currentHeight = placeable.height
val currentWidth = placeable.width
val newDiameter = maxOf(currentHeight, currentWidth)
val newScale = newDiameter * scale
layout(newScale.toInt(), newScale.toInt()) {
placeable.placeRelative(
((newScale - currentWidth) / 2).toInt(),
((newScale - currentHeight) / 2).toInt()
)
}
}
.border(2.dp, Color.Blue)
) {
content()
}
}
@Composable
fun PulsatingCircle2(content: @Composable () -> Unit) {
val infiniteTransition = rememberInfiniteTransition(label = "")
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 2f, // 2 to see if it does really something quickly
animationSpec = infiniteRepeatable(
animation = tween(1700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
), label = ""
)
var offset by remember {
mutableStateOf(IntOffset(0, 0))
}
Box(
modifier = Modifier
.border(2.dp, Color.Magenta)
.offset {
offset
}
.background(color = Color.Red, shape = CircleShape)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val currentHeight = placeable.height
val currentWidth = placeable.width
val newDiameter = maxOf(currentHeight, currentWidth)
val newScale = newDiameter * scale
offset = IntOffset(
-((newScale - currentWidth) / 2).toInt(),
-((newScale - currentHeight) / 2).toInt()
)
layout(newScale.toInt(), newScale.toInt()) {
placeable.placeRelative(
((newScale - currentWidth) / 2).toInt(),
((newScale - currentHeight) / 2).toInt()
)
}
}
.border(2.dp, Color.Blue)
) {
content()
}
}
With Modifier.drawBehind{}
fun Modifier.animateBackground(
color: Color
) = composed {
val infiniteTransition = rememberInfiniteTransition(label = "")
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 2f, // 2 to see if it does really something quickly
animationSpec = infiniteRepeatable(
animation = tween(1700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
), label = ""
)
Modifier.drawBehind {
val radius = (size.width.coerceAtLeast(size.height)) / 2
drawCircle(color = color, radius = radius * scale)
}
}
Demo
@Preview
@Composable
private fun Test() {
Column(
modifier = Modifier.padding(top = 30.dp, start = 30.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.border(2.dp, Color.Cyan)
) {
PulsatingCircle {
Image(
imageVector = Icons.Default.People,
contentDescription = null
)
}
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Yellow)
)
}
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.border(2.dp, Color.Cyan)
) {
PulsatingCircle2 {
Image(
imageVector = Icons.Default.People,
contentDescription = null
)
}
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Yellow)
)
}
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.border(2.dp, Color.Cyan)
) {
Image(
modifier = Modifier
.zIndex(4f)
.animateBackground(Color.Red),
imageVector = Icons.Default.People,
contentDescription = null
)
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Yellow)
)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论