feat: Optimize onboarding animations and improve page swiping performance

This commit is contained in:
k1ngsterr1
2026-01-15 22:40:24 +05:00
parent e7e6d23631
commit 80f5e436ee

View File

@@ -247,15 +247,17 @@ fun OnboardingScreen(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(150.dp), .height(150.dp),
// Pre-load adjacent pages for smooth swiping
beyondBoundsPageCount = 2,
flingBehavior = PagerDefaults.flingBehavior( flingBehavior = PagerDefaults.flingBehavior(
state = pagerState, state = pagerState,
lowVelocityAnimationSpec = tween( lowVelocityAnimationSpec = tween(
durationMillis = 300, durationMillis = 250,
easing = FastOutSlowInEasing easing = FastOutSlowInEasing
), ),
snapAnimationSpec = spring( snapAnimationSpec = spring(
dampingRatio = Spring.DampingRatioLowBouncy, dampingRatio = Spring.DampingRatioNoBouncy,
stiffness = Spring.StiffnessLow stiffness = Spring.StiffnessMedium
) )
) )
) { page -> ) { page ->
@@ -372,42 +374,20 @@ fun AnimatedRosettaLogo(
bookComposition: Any?, bookComposition: Any?,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val currentPage = pagerState.currentPage // Use derivedStateOf for optimized reads
val pageOffset = pagerState.currentPageOffsetFraction val currentPage by remember { derivedStateOf { pagerState.currentPage } }
// Animate scale and alpha based on swipe
val scale by animateFloatAsState(
targetValue = 1f - (pageOffset.absoluteValue * 0.08f),
animationSpec = tween(400, easing = FastOutSlowInEasing),
label = "scale"
)
val alpha by animateFloatAsState(
targetValue = 1f - (pageOffset.absoluteValue * 0.3f),
animationSpec = tween(400, easing = FastOutSlowInEasing),
label = "alpha"
)
Box( Box(
modifier = modifier modifier = modifier,
.graphicsLayer {
// Enable hardware acceleration
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
contentAlignment = Alignment.Center
) {
// Pre-render all animations to avoid lag
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
// Hardware layer for better performance
renderEffect = null
},
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
// Rosetta icon (page 0) with pulse animation like splash screen // Rosetta icon (page 0) with pulse animation like splash screen
if (currentPage == 0) { androidx.compose.animation.AnimatedVisibility(
visible = currentPage == 0,
enter = fadeIn(animationSpec = tween(200)),
exit = fadeOut(animationSpec = tween(200))
) {
Box(contentAlignment = Alignment.Center) {
val pulseScale by rememberInfiniteTransition(label = "pulse").animateFloat( val pulseScale by rememberInfiniteTransition(label = "pulse").animateFloat(
initialValue = 1f, initialValue = 1f,
targetValue = 1.1f, targetValue = 1.1f,
@@ -418,7 +398,7 @@ fun AnimatedRosettaLogo(
label = "pulseScale" label = "pulseScale"
) )
// Glow effect behind logo - same style as splash screen // Glow effect behind logo
Box( Box(
modifier = Modifier modifier = Modifier
.size(180.dp) .size(180.dp)
@@ -429,7 +409,7 @@ fun AnimatedRosettaLogo(
) )
) )
// Main logo - circular like splash screen // Main logo
Image( Image(
painter = painterResource(id = R.drawable.rosetta_icon), painter = painterResource(id = R.drawable.rosetta_icon),
contentDescription = "Rosetta Logo", contentDescription = "Rosetta Logo",
@@ -438,114 +418,100 @@ fun AnimatedRosettaLogo(
.clip(CircleShape) .clip(CircleShape)
) )
} }
}
// Fast page - idea animation (page 1) // Idea animation (page 1)
// Load adjacent pages for smooth swiping androidx.compose.animation.AnimatedVisibility(
val shouldLoadIdea = currentPage in 0..2 visible = currentPage == 1,
if (shouldLoadIdea) { enter = fadeIn(animationSpec = tween(200)),
exit = fadeOut(animationSpec = tween(200))
) {
ideaComposition?.let { comp -> ideaComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState( val progress by animateLottieCompositionAsState(
composition = lottieComp, composition = lottieComp,
iterations = 1, iterations = 1,
isPlaying = currentPage == 1, isPlaying = true,
speed = 1.2f // Faster for smoother perception speed = 1.5f
) )
if (currentPage == 1) {
LottieAnimation( LottieAnimation(
composition = lottieComp, composition = lottieComp,
progress = { progress }, progress = { progress },
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize()
.graphicsLayer {
// Hardware acceleration for smooth rendering
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true maintainOriginalImageBounds = true
) )
} }
} }
}
// Free page - money animation (page 2) // Money animation (page 2)
val shouldLoadMoney = currentPage in 1..3 androidx.compose.animation.AnimatedVisibility(
if (shouldLoadMoney) { visible = currentPage == 2,
enter = fadeIn(animationSpec = tween(200)),
exit = fadeOut(animationSpec = tween(200))
) {
moneyComposition?.let { comp -> moneyComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState( val progress by animateLottieCompositionAsState(
composition = lottieComp, composition = lottieComp,
iterations = 1, iterations = 1,
isPlaying = currentPage == 2, isPlaying = true,
speed = 1.2f speed = 1.5f
) )
if (currentPage == 2) {
LottieAnimation( LottieAnimation(
composition = lottieComp, composition = lottieComp,
progress = { progress }, progress = { progress },
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true maintainOriginalImageBounds = true
) )
} }
} }
}
// Secure page - lock animation (page 3) // Lock animation (page 3)
val shouldLoadLock = currentPage in 2..4 androidx.compose.animation.AnimatedVisibility(
if (shouldLoadLock) { visible = currentPage == 3,
enter = fadeIn(animationSpec = tween(200)),
exit = fadeOut(animationSpec = tween(200))
) {
lockComposition?.let { comp -> lockComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState( val progress by animateLottieCompositionAsState(
composition = lottieComp, composition = lottieComp,
iterations = 1, iterations = 1,
isPlaying = currentPage == 3, isPlaying = true,
speed = 1.2f speed = 1.5f
) )
if (currentPage == 3) {
LottieAnimation( LottieAnimation(
composition = lottieComp, composition = lottieComp,
progress = { progress }, progress = { progress },
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true maintainOriginalImageBounds = true
) )
} }
} }
}
// Private page - book animation (page 4) // Book animation (page 4)
val shouldLoadBook = currentPage in 3..4 androidx.compose.animation.AnimatedVisibility(
if (shouldLoadBook) { visible = currentPage == 4,
enter = fadeIn(animationSpec = tween(200)),
exit = fadeOut(animationSpec = tween(200))
) {
bookComposition?.let { comp -> bookComposition?.let { comp ->
val lottieComp = comp as? com.airbnb.lottie.LottieComposition val lottieComp = comp as? com.airbnb.lottie.LottieComposition
val progress by animateLottieCompositionAsState( val progress by animateLottieCompositionAsState(
composition = lottieComp, composition = lottieComp,
iterations = 1, iterations = 1,
isPlaying = currentPage == 4, isPlaying = true,
speed = 1.2f speed = 1.5f
) )
if (currentPage == 4) {
LottieAnimation( LottieAnimation(
composition = lottieComp, composition = lottieComp,
progress = { progress }, progress = { progress },
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize()
.graphicsLayer {
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
},
maintainOriginalImageBounds = true maintainOriginalImageBounds = true
) )
} }
} }
} }
}
}
} }
@Composable @Composable