nav: spring slide/fade screen transitions (Calendula feel)
Drive the NavHost with the motion scheme's fastSpatialSpec: forward fades in over a held, static background; back (and the predictive-back drag) slides the top screen out to the right, revealing the screen beneath unmoved — the same overlay feel as Calendula, instead of the default navigation-compose transition. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
package de.jeanlucmakiola.floret.ui.navigation
|
package de.jeanlucmakiola.floret.ui.navigation
|
||||||
|
|
||||||
|
import androidx.compose.animation.EnterTransition
|
||||||
|
import androidx.compose.animation.ExitTransition
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -28,11 +33,20 @@ import de.jeanlucmakiola.floret.ui.tasklist.TaskListViewModel
|
|||||||
@Composable
|
@Composable
|
||||||
fun FloretNavHost(modifier: Modifier = Modifier) {
|
fun FloretNavHost(modifier: Modifier = Modifier) {
|
||||||
val nav = rememberNavController()
|
val nav = rememberNavController()
|
||||||
|
val slide = rememberNavSlideSpec()
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = nav,
|
navController = nav,
|
||||||
startDestination = Dest.LISTS,
|
startDestination = Dest.LISTS,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
// Only the screen on top moves; the background is always held static.
|
||||||
|
// Forward is a plain fade-in over the held screen — calm, not a slide.
|
||||||
|
// Back (and the predictive-back drag, which drives popExit) is the snappy
|
||||||
|
// slide-out to the right, revealing the held screen unmoved.
|
||||||
|
enterTransition = { fadeIn() },
|
||||||
|
exitTransition = { ExitTransition.None },
|
||||||
|
popEnterTransition = { EnterTransition.None },
|
||||||
|
popExitTransition = { slideOutHorizontally(slide) { it } + fadeOut() },
|
||||||
) {
|
) {
|
||||||
composable(Dest.LISTS) {
|
composable(Dest.LISTS) {
|
||||||
ListsScreen(
|
ListsScreen(
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package de.jeanlucmakiola.floret.ui.navigation
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The horizontal slide spec for screen-to-screen navigation: the *fast*
|
||||||
|
* spring-physics spec from the active motion scheme — snappy with a subtle
|
||||||
|
* springy settle, rather than a fixed easing curve. Same choice as Calendula's
|
||||||
|
* calendar slide, so the two apps move the same way.
|
||||||
|
*
|
||||||
|
* Read in composable scope so the non-composable `NavHost` transition lambdas
|
||||||
|
* can capture it.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
|
@Composable
|
||||||
|
fun rememberNavSlideSpec(): FiniteAnimationSpec<IntOffset> =
|
||||||
|
MaterialTheme.motionScheme.fastSpatialSpec()
|
||||||
Reference in New Issue
Block a user