feat: Optimize onboarding animations and improve page swiping performance
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user