Skip to content

Commit

Permalink
在非 COMPACT 设备上去除 navigation 的 slide 动画, 改用纯 fade
Browse files Browse the repository at this point in the history
  • Loading branch information
Him188 committed Nov 10, 2024
1 parent d43269d commit ec5f577
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 45 deletions.
18 changes: 12 additions & 6 deletions app/shared/src/commonMain/kotlin/ui/main/AniAppContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
Expand All @@ -51,7 +52,8 @@ import me.him188.ani.app.ui.cache.details.MediaCacheDetailsPage
import me.him188.ani.app.ui.cache.details.MediaCacheDetailsPageViewModel
import me.him188.ani.app.ui.cache.details.MediaDetailsLazyGrid
import me.him188.ani.app.ui.foundation.layout.desktopTitleBar
import me.him188.ani.app.ui.foundation.theme.AniNavigationMotionScheme
import me.him188.ani.app.ui.foundation.theme.LocalNavigationMotionScheme
import me.him188.ani.app.ui.foundation.theme.NavigationMotionScheme
import me.him188.ani.app.ui.profile.BangumiOAuthViewModel
import me.him188.ani.app.ui.profile.auth.BangumiOAuthScene
import me.him188.ani.app.ui.profile.auth.BangumiTokenAuthPage
Expand Down Expand Up @@ -87,7 +89,10 @@ fun AniAppContent(
aniNavigator.setNavController(navigator)

Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
CompositionLocalProvider(LocalNavigator provides aniNavigator) {
CompositionLocalProvider(
LocalNavigator provides aniNavigator,
LocalNavigationMotionScheme provides NavigationMotionScheme.calculate(),
) {
AniAppContentImpl(aniNavigator, initialRoute, Modifier.fillMaxSize())
}
}
Expand All @@ -104,17 +109,18 @@ private fun AniAppContentImpl(
val windowInsetsWithoutTitleBar = ScaffoldDefaults.contentWindowInsets
val windowInsets = ScaffoldDefaults.contentWindowInsets
.add(WindowInsets.desktopTitleBar()) // Compose 目前不支持这个所以我们要自己加上
val navMotionScheme by rememberUpdatedState(NavigationMotionScheme.current)

SharedTransitionLayout {
NavHost(navController, startDestination = initialRoute, modifier) {
val enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition? =
{ AniNavigationMotionScheme.enterTransition }
{ navMotionScheme.enterTransition }
val exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition? =
{ AniNavigationMotionScheme.exitTransition }
{ navMotionScheme.exitTransition }
val popEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition? =
{ AniNavigationMotionScheme.popEnterTransition }
{ navMotionScheme.popEnterTransition }
val popExitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition? =
{ AniNavigationMotionScheme.popExitTransition }
{ navMotionScheme.popExitTransition }

composable<NavRoutes.Welcome>(
enterTransition = enterTransition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import me.him188.ani.app.ui.foundation.animation.StandardAccelerate
import me.him188.ani.app.ui.foundation.theme.AniNavigationMotionScheme
import me.him188.ani.app.ui.foundation.theme.AniThemeDefaults.feedItemFadeOutSpec
import me.him188.ani.app.ui.foundation.theme.EasingDurations
import me.him188.ani.app.ui.foundation.theme.NavigationMotionScheme

// 把过渡动画改为 fade 而不是带有回弹的 spring
@ExperimentalMaterial3AdaptiveApi
Expand All @@ -43,6 +43,7 @@ fun ThreePaneScaffoldScope.ListDetailAnimatedPane(
scaffoldStateTransition.currentState[role] != PaneAdaptedValue.Hidden &&
scaffoldStateTransition.targetState[role] != PaneAdaptedValue.Hidden
// val animateFraction = { scaffoldStateTransitionFraction }
val navMotionScheme = NavigationMotionScheme.current
scaffoldStateTransition.AnimatedVisibility(
visible = { value: ThreePaneScaffoldValue -> value[role] != PaneAdaptedValue.Hidden },
modifier =
Expand All @@ -61,11 +62,11 @@ fun ThreePaneScaffoldScope.ListDetailAnimatedPane(
}

role == ListDetailPaneScaffoldRole.List -> {
AniNavigationMotionScheme.popEnterTransition
navMotionScheme.popEnterTransition
}

role == ListDetailPaneScaffoldRole.Detail -> {
AniNavigationMotionScheme.enterTransition
navMotionScheme.enterTransition
}

else -> {
Expand All @@ -84,11 +85,11 @@ fun ThreePaneScaffoldScope.ListDetailAnimatedPane(
}

role == ListDetailPaneScaffoldRole.List -> {
AniNavigationMotionScheme.exitTransition
navMotionScheme.exitTransition
}

role == ListDetailPaneScaffoldRole.Detail -> {
AniNavigationMotionScheme.popExitTransition
navMotionScheme.popExitTransition
}

else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,20 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.IntOffset
import androidx.window.core.layout.WindowSizeClass
import me.him188.ani.app.ui.foundation.animation.EmphasizedAccelerateEasing
import me.him188.ani.app.ui.foundation.animation.EmphasizedDecelerateEasing
import me.him188.ani.app.ui.foundation.animation.StandardAccelerate
import me.him188.ani.app.ui.foundation.animation.StandardDecelerate
import me.him188.ani.app.ui.foundation.layout.isCompact
import kotlin.math.roundToInt

@Stable
Expand Down Expand Up @@ -164,40 +169,86 @@ object EasingDurations {


@Stable
object AniNavigationMotionScheme {
// https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration#e5b958f0-435d-4e84-aed4-8d1ea395fa5c
private const val enterDuration = 500
private const val exitDuration = 200
@Immutable
data class NavigationMotionScheme(
val enterTransition: EnterTransition,
val exitTransition: ExitTransition,
val popEnterTransition: EnterTransition,
val popExitTransition: ExitTransition,
) {
companion object {
inline val current
@Composable
get() = LocalNavigationMotionScheme.current

// https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration#e5b958f0-435d-4e84-aed4-8d1ea395fa5c
private const val enterDuration = 500
private const val exitDuration = 200

// https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration#26a169fb-caf3-445e-8267-4f1254e3e8bb
// https://developer.android.com/develop/ui/compose/animation/shared-elements
private val enterEasing = EmphasizedDecelerateEasing
private val exitEasing = LinearOutSlowInEasing

// https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration#26a169fb-caf3-445e-8267-4f1254e3e8bb
// https://developer.android.com/develop/ui/compose/animation/shared-elements
private val enterEasing = EmphasizedDecelerateEasing
private val exitEasing = LinearOutSlowInEasing

@Stable
val enterTransition: EnterTransition =
slideInHorizontally(
tween(
enterDuration,
easing = enterEasing,
),
) { (it * (1f / 5)).roundToInt() }
.plus(fadeIn(tween(enterDuration, easing = enterEasing)))


@Stable
val exitTransition: ExitTransition =
fadeOut(tween(exitDuration, easing = exitEasing))

@Stable
val popEnterTransition = fadeIn(tween(enterDuration, easing = enterEasing))
@Composable
fun calculate(windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass): NavigationMotionScheme {
val useSlide = windowSizeClass.windowWidthSizeClass.isCompact

val enterTransition: EnterTransition = run {
if (useSlide) {
val slideIn = slideInHorizontally(
tween(
enterDuration,
easing = enterEasing,
),
initialOffsetX = { (it * (1f / 5)).roundToInt() },
)
val fadeIn = fadeIn(tween(enterDuration, easing = enterEasing))
slideIn.plus(fadeIn)
} else {
fadeIn(tween(enterDuration, delayMillis = exitDuration, easing = enterEasing))
}
}

val exitTransition: ExitTransition =
fadeOut(tween(exitDuration, easing = exitEasing))

val popEnterTransition = run {
if (useSlide) {
fadeIn(tween(enterDuration, easing = enterEasing))
} else {
fadeIn(tween(enterDuration, delayMillis = exitDuration, easing = enterEasing)) // clean fade
}
}

// 从页面 A 回到上一个页面 B, 切走页面 A 的动画
val popExitTransition: ExitTransition = run {
val fadeOut = fadeOut(tween(exitDuration, easing = exitEasing))
if (useSlide) {
val slide = slideOutHorizontally(
tween(
exitDuration,
easing = exitEasing,
),
targetOffsetX = { (it * (1f / 7)).roundToInt() },
)
slide.plus(fadeOut)
} else {
fadeOut
}
}

return NavigationMotionScheme(
enterTransition = enterTransition,
exitTransition = exitTransition,
popEnterTransition = popEnterTransition,
popExitTransition = popExitTransition,
)
}
}
}

// 从页面 A 回到上一个页面 B, 切走页面 A 的动画
@Stable
val popExitTransition = slideOutHorizontally(
tween(
exitDuration,
easing = exitEasing,
),
) { (it * (1f / 7)).roundToInt() }.plus(fadeOut(tween(exitDuration, easing = exitEasing)))
@Stable
val LocalNavigationMotionScheme = compositionLocalOf<NavigationMotionScheme> {
error("No LocalNavigationMotionScheme provided")
}

0 comments on commit ec5f577

Please sign in to comment.