Skip to content

Commit dda7f28

Browse files
committed
Added keyframe and curve animations
1 parent 3c95bdf commit dda7f28

File tree

3 files changed

+216
-1
lines changed

3 files changed

+216
-1
lines changed

app/src/main/java/com/guru/composecookbook/ui/animation/AnimationScreen.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.compose.foundation.lazy.LazyColumn
66
import androidx.compose.foundation.lazy.rememberLazyListState
77
import androidx.compose.material.icons.Icons
88
import androidx.compose.material.icons.filled.PlayArrow
9+
import androidx.compose.material3.Divider
910
import androidx.compose.material3.ExperimentalMaterial3Api
1011
import androidx.compose.material3.IconButton
1112
import androidx.compose.material3.Scaffold
@@ -68,6 +69,9 @@ fun AnimationScreenContent(
6869
modifier = modifier,
6970
) {
7071
item { Spacer(modifier = Modifier.padding(4.dp)) }
72+
item { TitleText(title = "Modern Animations") }
73+
item { ModernAnimations() }
74+
item { Divider() }
7175
item { TitleText(title = "State Animations(Fire and forget)") }
7276
item { AnimationsForStates() }
7377
item { AnimationsWithVisibilityApi() }
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package com.guru.composecookbook.ui.animation
2+
3+
import androidx.compose.animation.AnimatedContent
4+
import androidx.compose.animation.ExperimentalAnimationApi
5+
import androidx.compose.animation.SizeTransform
6+
import androidx.compose.animation.core.EaseInOut
7+
import androidx.compose.animation.core.LinearOutSlowInEasing
8+
import androidx.compose.animation.core.RepeatMode
9+
import androidx.compose.animation.core.animateFloat
10+
import androidx.compose.animation.core.infiniteRepeatable
11+
import androidx.compose.animation.core.keyframes
12+
import androidx.compose.animation.core.rememberInfiniteTransition
13+
import androidx.compose.animation.core.tween
14+
import androidx.compose.animation.fadeIn
15+
import androidx.compose.animation.fadeOut
16+
import androidx.compose.animation.slideInVertically
17+
import androidx.compose.animation.slideOutVertically
18+
import androidx.compose.animation.togetherWith
19+
import androidx.compose.animation.with
20+
import androidx.compose.foundation.background
21+
import androidx.compose.foundation.layout.*
22+
import androidx.compose.foundation.shape.CircleShape
23+
import androidx.compose.material.icons.Icons
24+
import androidx.compose.material.icons.filled.Favorite
25+
import androidx.compose.material3.*
26+
import androidx.compose.runtime.*
27+
import androidx.compose.ui.Alignment
28+
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.draw.alpha
30+
import androidx.compose.ui.draw.clip
31+
import androidx.compose.ui.graphics.Color
32+
import androidx.compose.ui.graphics.graphicsLayer
33+
import androidx.compose.ui.unit.dp
34+
import com.guru.composecookbook.theme.green200
35+
import com.guru.composecookbook.theme.purple
36+
import com.guru.composecookbook.ui.utils.SubtitleText
37+
import kotlinx.coroutines.delay
38+
import kotlinx.coroutines.launch
39+
40+
@Composable
41+
fun ModernAnimations() {
42+
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
43+
SubtitleText(subtitle = "Modern Jetpack Compose Animations")
44+
Spacer(modifier = Modifier.height(16.dp))
45+
46+
// 1. Like Button Animation with Keyframes
47+
SubtitleText(subtitle = "Like Button Animation with Keyframes")
48+
LikeButtonAnimation()
49+
Divider(modifier = Modifier.padding(vertical = 16.dp))
50+
51+
// 2. Animated Content with Combined Animations
52+
SubtitleText(subtitle = "Animated Content with Combined Animations")
53+
AnimatedCounter()
54+
Divider(modifier = Modifier.padding(vertical = 16.dp))
55+
56+
// 3. Shimmer Loading Animation
57+
SubtitleText(subtitle = "Shimmer Loading Animation")
58+
ShimmerLoadingAnimation()
59+
Divider(modifier = Modifier.padding(vertical = 16.dp))
60+
61+
// 4. Pulse Animation
62+
SubtitleText(subtitle = "Pulse Animation")
63+
PulseAnimation()
64+
Divider(modifier = Modifier.padding(vertical = 16.dp))
65+
66+
// 5. Wave Loading Animation
67+
WaveLoadingAnimation()
68+
}
69+
}
70+
71+
@Composable
72+
fun LikeButtonAnimation() {
73+
var liked by remember { mutableStateOf(false) }
74+
val scope = rememberCoroutineScope()
75+
var scale by remember { mutableStateOf(1f) }
76+
77+
IconButton(
78+
onClick = {
79+
liked = !liked
80+
scope.launch {
81+
scale = 1.3f
82+
delay(100)
83+
scale = 1f
84+
}
85+
},
86+
modifier = Modifier.graphicsLayer(scaleX = scale, scaleY = scale)
87+
) {
88+
Icon(
89+
Icons.Default.Favorite,
90+
contentDescription = "Like",
91+
tint = if (liked) Color.Red else Color.Gray,
92+
modifier = Modifier.size(24.dp)
93+
)
94+
}
95+
}
96+
97+
@OptIn(ExperimentalAnimationApi::class)
98+
@Composable
99+
fun AnimatedCounter() {
100+
var count by remember { mutableStateOf(0) }
101+
102+
Row(verticalAlignment = Alignment.CenterVertically) {
103+
Button(onClick = { count++ }) {
104+
Text("Count: ")
105+
AnimatedContent(
106+
targetState = count,
107+
transitionSpec = {
108+
slideInVertically { it } + fadeIn() togetherWith
109+
slideOutVertically { -it } + fadeOut() using
110+
SizeTransform(clip = false)
111+
}
112+
) { targetCount ->
113+
Text("$targetCount")
114+
}
115+
}
116+
}
117+
}
118+
119+
@Composable
120+
fun ShimmerLoadingAnimation() {
121+
val infiniteTransition = rememberInfiniteTransition()
122+
val translateAnim =
123+
infiniteTransition.animateFloat(
124+
initialValue = 0f,
125+
targetValue = 1000f,
126+
animationSpec =
127+
infiniteRepeatable(
128+
animation = tween(1500, easing = LinearOutSlowInEasing),
129+
repeatMode = RepeatMode.Restart
130+
)
131+
)
132+
133+
Box(
134+
modifier =
135+
Modifier.fillMaxWidth()
136+
.height(100.dp)
137+
.clip(MaterialTheme.shapes.medium)
138+
.background(green200)
139+
.background(
140+
brush =
141+
androidx.compose.ui.graphics.Brush.linearGradient(
142+
colors = listOf(Color.Transparent, Color.White.copy(alpha = 0.4f), Color.Transparent),
143+
start = androidx.compose.ui.geometry.Offset(translateAnim.value - 500f, 0f),
144+
end = androidx.compose.ui.geometry.Offset(translateAnim.value, 500f)
145+
)
146+
)
147+
)
148+
}
149+
150+
@Composable
151+
fun PulseAnimation() {
152+
val infiniteTransition = rememberInfiniteTransition()
153+
val scale by
154+
infiniteTransition.animateFloat(
155+
initialValue = 1f,
156+
targetValue = 1.2f,
157+
animationSpec =
158+
infiniteRepeatable(
159+
animation = tween(1000, easing = EaseInOut),
160+
repeatMode = RepeatMode.Reverse
161+
)
162+
)
163+
164+
Box(
165+
modifier =
166+
Modifier.size(60.dp)
167+
.graphicsLayer(scaleX = scale, scaleY = scale)
168+
.clip(CircleShape)
169+
.background(purple)
170+
)
171+
}
172+
173+
@Composable
174+
fun WaveLoadingAnimation() {
175+
val waves = 3
176+
val infiniteTransition = rememberInfiniteTransition()
177+
178+
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
179+
repeat(waves) { index ->
180+
val delay = index * 100
181+
val transition by
182+
infiniteTransition.animateFloat(
183+
initialValue = 0f,
184+
targetValue = 1f,
185+
animationSpec =
186+
infiniteRepeatable(
187+
animation =
188+
keyframes {
189+
durationMillis = 1200
190+
0f at 0 with LinearOutSlowInEasing
191+
1f at 600 with LinearOutSlowInEasing
192+
0f at 1200 with LinearOutSlowInEasing
193+
},
194+
initialStartOffset = androidx.compose.animation.core.StartOffset(delay)
195+
)
196+
)
197+
198+
Box(
199+
modifier =
200+
Modifier.padding(4.dp)
201+
.size(20.dp)
202+
.graphicsLayer {
203+
scaleY = transition
204+
alpha = transition
205+
}
206+
.clip(CircleShape)
207+
.background(MaterialTheme.colorScheme.primary)
208+
)
209+
}
210+
}
211+
}

app/src/main/java/com/guru/composecookbook/ui/animation/VisibilityAnimations.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ import androidx.compose.foundation.layout.height
2323
import androidx.compose.foundation.layout.padding
2424
import androidx.compose.foundation.layout.size
2525
import androidx.compose.foundation.layout.width
26-
import androidx.compose.material.Divider
2726
import androidx.compose.material.icons.Icons
2827
import androidx.compose.material.icons.filled.PlayCircleFilled
2928
import androidx.compose.material.icons.filled.RemoveRedEye
3029
import androidx.compose.material3.Button
30+
import androidx.compose.material3.Divider
3131
import androidx.compose.material3.FloatingActionButton
3232
import androidx.compose.material3.Icon
3333
import androidx.compose.material3.IconButton

0 commit comments

Comments
 (0)