How to do my image to rotate infinitely?
This is my code but animation does not work
val angle: Float by animateFloatAsState(
targetValue = 360F,
animationSpec = infiniteRepeatable(
tween(2000))
)
Image(
painter = painterResource(R.drawable.sonar_scanner),
"image",
Modifier
.fillMaxSize()
.rotate(angle),
contentScale = ContentScale.Fit
)
You can use the InfiniteTransition using rememberInfiniteTransition.
Something like
val infiniteTransition = rememberInfiniteTransition()
val angle by infiniteTransition.animateFloat(
initialValue = 0F,
targetValue = 360F,
animationSpec = infiniteRepeatable(
animation = tween(2000, easing = LinearEasing)
)
)
Just a note.
Instead of using
Modifier.rotate(angle)
You can use
Modifier
.graphicsLayer {
rotationZ = angle
}
As you can check in the doc:
Prefer this version when you have layer properties backed by a androidx.compose.runtime.State or an animated value as reading a state inside block will only cause the layer properties update without triggering recomposition and relayout.
You should use the pre-defined API for infinite animations for such use cases in my opinion.
val infiniteTransition = rememberInfiniteTransition()
val angle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 1000
}
)
)
Related
I'm trying to achieve a smooth animation of a simple round timer. Like this, but smoother
However it just skips to targetValue immediately and that's it there's no animation at all. I'm trying to do it like this:
#Composable
private fun SampleTimer(duration: Int, modifier: Modifier = Modifier) {
var animatedPercentage by remember { mutableStateOf(1f) }
LaunchedEffect(Unit) {
animate(
initialValue = 1f,
targetValue = 0f,
animationSpec = infiniteRepeatable(
tween(
durationMillis = duration.seconds.inWholeMilliseconds.toInt(),
easing = LinearEasing,
),
),
) { value, _ ->
animatedPercentage = value
}
}
val arcColor = MaterialTheme.colors.primaryVariant
Canvas(
modifier = modifier,
) {
drawArc(
color = arcColor,
useCenter = true,
startAngle = -90f,
sweepAngle = -360f * animatedPercentage,
)
}
}
Why does this happen, what am I missing here?
You can use an Animatable state. The angle will animate from 0–360°.
Something like:
val angle = remember {
Animatable(0f)
}
LaunchedEffect(angle) {
launch {
angle.animateTo(360f, animationSpec =
infiniteRepeatable(
tween(
durationMillis = 5000,
easing = LinearEasing,
),
)
)
}
}
val arcColor = Red
Canvas(
modifier = Modifier.size(100.dp),
) {
drawArc(
color = arcColor,
useCenter = true,
startAngle = -90f,
sweepAngle = -angle.value,
)
}
The problem was that the animations were turned off in developer settings on my device, and I forgot that
Below code is in java. We need to do same thing using jetpack compose. please help us to achieve this.
val flashAnimatorSet = AnimatorSet()
val layer = ObjectAnimator.ofInt(
image,
alpha,
255,
77
)
layer.repeatMode = ValueAnimator.REVERSE
layer.repeatCount = ObjectAnimator.INFINITE
flashAnimatorSet.play(lightLayer)
flashAnimatorSet.duration = 100L
flashAnimatorSet.interpolator = AccelerateDecelerateInterpolator()
return flashAnimatorSet
You can use a InfiniteRepeatableSpec to repeat the provided animation infinite amount of times.
Something like:
val infiniteTransition = rememberInfiniteTransition()
val alpha by infiniteTransition.animateFloat(
initialValue = 1F,
targetValue = 0.28F,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse
)
)
Then apply it to your Composable, for example:
Image(
painterResource(id = R.drawable.xxx),
modifier = Modifier
.graphicsLayer {
this.alpha = alpha
},
contentDescription = "contentDescription"
)
I am trying to make shaking animation of shape in Jetpack Compose. I want to use this animation to show error when user enters invalid Pin code. But all I can find is slide in, slide out animations and some scale animations. Any ideas how I can accomplish this?
Update:
After #Thracian answer. I used code as below, shaking my items horizontally:
fun Modifier.shake(enabled: Boolean, onAnimationFinish: () -> Unit) = composed(
factory = {
val distance by animateFloatAsState(
targetValue = if (enabled) 15f else 0f,
animationSpec = repeatable(
iterations = 8,
animation = tween(durationMillis = 50, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
finishedListener = { onAnimationFinish.invoke() }
)
Modifier.graphicsLayer {
translationX = if (enabled) distance else 0f
}
},
inspectorInfo = debugInspectorInfo {
name = "shake"
properties["enabled"] = enabled
}
)
Gif is slower than actual animation unfortunately but it gives an idea of outcome.
This can be done in many ways. You should change scaleX or scaleY or both in short time duration to have a shake effect. If you wish to have rotation change rotationZ of Modifier.graphicsLayer either
#Composable
private fun ShakeAnimationSamples() {
Column(modifier = Modifier
.fillMaxSize()
.padding(10.dp)) {
var enabled by remember {
mutableStateOf(false)
}
val scale by animateFloatAsState(
targetValue = if (enabled) .9f else 1f,
animationSpec = repeatable(
iterations = 5,
animation = tween(durationMillis = 50, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
),
finishedListener = {
enabled = false
}
)
val infiniteTransition = rememberInfiniteTransition()
val scaleInfinite by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = .85f,
animationSpec = infiniteRepeatable(
animation = tween(30, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
val rotation by infiniteTransition.animateFloat(
initialValue = -10f,
targetValue = 10f,
animationSpec = infiniteRepeatable(
animation = tween(30, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.graphicsLayer {
scaleX = if (enabled) scale else 1f
scaleY = if (enabled) scale else 1f
}
.background(Color.Red, CircleShape)
.size(50.dp)
.padding(10.dp)
)
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.graphicsLayer {
scaleX = scaleInfinite
scaleY = scaleInfinite
rotationZ = rotation
}
.background(Color.Red, CircleShape)
.size(50.dp)
.padding(10.dp)
)
Button(onClick = { enabled = !enabled }) {
Text("Animation enabled: $enabled")
}
}
}
Also you can do it as a Modifier either
fun Modifier.shake(enabled: Boolean) = composed(
factory = {
val scale by animateFloatAsState(
targetValue = if (enabled) .9f else 1f,
animationSpec = repeatable(
iterations = 5,
animation = tween(durationMillis = 50, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Modifier.graphicsLayer {
scaleX = if (enabled) scale else 1f
scaleY = if (enabled) scale else 1f
}
},
inspectorInfo = debugInspectorInfo {
name = "shake"
properties["enabled"] = enabled
}
)
Usage
Icon(
imageVector = Icons.Default.NotificationsActive,
contentDescription = null,
tint = Color.White,
modifier = Modifier
.shake(enabled)
.background(Color.Red, CircleShape)
.size(50.dp)
.padding(10.dp)
)
I am trying to achieve translate animation in Jetpack compose but i am not able to find Suitable Source for this.Can any one Help me to achieve translate Animation in jetpack compose in which i can set start and edning positionl Manually..
The alternative of translate animation in jetpack compose is OFFSET ANIMATION
yes, I was able to achieve this through offset animation.I am sharing the code below with comments in detail so it will be easier for the reader to understand it
// Courtine Scope to Run the animation in thread
val coroutineScope = rememberCoroutineScope()
val offsetX = remember { Animatable(0f) }
val offsetY = remember { Animatable(0f) }
Image(
painter = rememberDrawablePainter(
ContextCompat.getDrawable(
context,
R.drawable.image
)
),
contentDescription = "s", contentScale = ContentScale.Crop,
modifier = Modifier
.offset {
IntOffset(
offsetX.value.toInt(),
offsetY.value.toInt()
)
}
.width(300.dp)
.height(300.dp)
)
//Finally run the animation on the Click of your button or whenever you wants to start it...
coroutineScope.launch {
launch {
offsetXFirst.animateTo(
targetValue = targetValue,
animationSpec = tween(
durationMillis = 2000,
delayMillis = 0))}
launch {
offsetYFirst.animateTo(
targetValue = size.height.toFloat(),
animationSpec = tween(
durationMillis = 2000,
delayMillis = 0))}
}
Using the offset was my solution as well. However used animateDpAsState instead. There a tab indicator is moved on the x axis:
val offsetState = animateDpAsState(targetValue = targetPositionDp)
Box(modifier = Modifier
.offset(offsetState.value, 0.dp)
.background(color = Color.Red)
.size(tabWidth, tabHeight))
In the past (before alpha11), I can animate a value from 0 to 1 upon triggering the composable function as below, where I can set initialValue and also have onActive with aniumateTo.
val animatedProgress = animatedFloat(0f)
onActive {
animatedProgress.animateTo(
targetValue = 1f,
anim = infiniteRepeatable(
animation =
tween(durationMillis = 2000, easing = LinearEasing),
)
)
}
val t = animatedProgress.value
However, now in alpha13, I cannot find a way to set initialValue, or animateTo. The onActive is also now deprecated.
I coded as below
val floatAnimation = animateFloatAsState(
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 2000, easing = LinearEasing),
)
)
How can I...
Set initial value of 0
Starting the animation (without needing a state boolean to kick it off)
Animate from 0 to 1 repeatedly
You can use the Animatable API and the LaunchedEffect composable. You don't need a boolean to start the animation.
Something like:
val animatedAlpha = remember { Animatable(0f) }
Box(
Modifier
.background(color = (Color.Blue.copy(alpha = animatedAlpha.value)))
.size(100.dp,100.dp)
)
LaunchedEffect(animatedAlpha) {
animatedAlpha.animateTo(1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 2000, easing = LinearEasing)
))
}
Looks like I have to use a boolean to change the state and use LaunchEffect to start and change the state as below.
var start by remember{ mutableStateOf(false) }
val floatAnimation = animateFloatAsState(
targetValue = if (start) 1f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 2000, easing = LinearEasing),
)
)
LaunchedEffect(true) {
start = true
}
val t = floatAnimation.value
Not sure if this is the best way to code around it.