Benjamin Deroche
03/22/2022, 9:53 AMBox(
modifier = Modifier.fillMaxSize()
) {
val infiniteTransition: InfiniteTransition = rememberInfiniteTransition()
val initialSize: Float = 72f
val pulsingSize: Float = 88f
val size: Float by infiniteTransition.animateFloat(
initialValue = initialSize,
targetValue = pulsingSize,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = LinearEasing
),
repeatMode = RepeatMode.Reverse
)
)
val paddingReduction: Float = (size - initialSize) / 2
FloatingActionButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding((16f - paddingReduction).dp)
.size(size.dp),
onClick = {}
) {
Icon(
imageVector = Icons.Default.ArrowUpward,
contentDescription = "To the top!"
)
}
}
f.babic
03/22/2022, 9:54 AMBenjamin Deroche
03/22/2022, 10:02 AMval infiniteTransition: InfiniteTransition = rememberInfiniteTransition()
val initialSize: Dp = 72.dp
val pulsingSize: Dp = 88.dp
val size: Dp by infiniteTransition.animateValue(
initialValue = initialSize,
targetValue = pulsingSize,
typeConverter = Dp.VectorConverter,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse
)
)
FloatingActionButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(16.dp - (size - initialSize) / 2)
.size(size),
backgroundColor = backgroundColor,
contentColor = contentColor,
onClick = {}
) {
Icon(
imageVector = Icons.Default.ArrowUpward,
contentDescription = "To the top!"
)
}
f.babic
03/22/2022, 10:05 AMBenjamin Deroche
03/22/2022, 10:19 AMf.babic
03/22/2022, 10:26 AMBenjamin Deroche
03/22/2022, 10:46 AMModifier.scale()
instead of Modifier.size()
on the Button. The icon inside the button grow too, so it's not exactly the animation I was trying to achieve, but at least it's smooth.f.babic
03/22/2022, 10:59 AMandrew
03/22/2022, 2:20 PM@Composable
fun Pulse(
modifier: Modifier = Modifier,
tint: Color = LocalContentColor.current,
active: Boolean = true,
bounded: Boolean = true,
count: Int = 3,
duration: Int = 1000,
) {
if (!active) return
val infiniteTransition = rememberInfiniteTransition()
val pulses = buildList {
for (i in 0 until count) {
add(infiniteTransition.animateFloat(
initialValue = 0F,
targetValue = 1F,
animationSpec = infiniteRepeatable(
animation = tween(duration * count, easing = FastOutSlowInEasing),
initialStartOffset = StartOffset(i * duration),
)
))
}
}
Canvas(modifier.then(if (bounded) Modifier.clipToBounds() else Modifier)) {
val (a, b) = size
val r = sqrt(a.pow(2) + b.pow(2)) / 2
pulses.forEach {
val progress = it.value
scale(progress) {
drawCircle(tint.copy(alpha = (1F - progress) * 0.12F), r)
}
}
}
}
FloatingActionButton(
{},
Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(16.dp),
backgroundColor = Theme.colors.primary,
) {
Icon(Icons.Household.ic_fan_mode_on)
Pulse(Modifier.size(56.dp))
}
Benjamin Deroche
03/22/2022, 4:34 PMandrew
03/22/2022, 4:35 PMBenjamin Deroche
03/22/2022, 4:41 PMandrew
03/22/2022, 4:41 PMBenjamin Deroche
03/23/2022, 9:35 AMdrawCircle
accept an optional parameter alpha
so you don't have to use tint.copy
val pulses = List(count) { i ->
infiniteTransition.animateFloat(
initialValue = 0F,
targetValue = 1F,
animationSpec = infiniteRepeatable(
animation = tween(duration * count, easing = FastOutSlowInEasing),
initialStartOffset = StartOffset(i * duration),
)
)
}
andrew
03/23/2022, 2:38 PM