refactor: 优化 FAB 共享元素转场动画
This commit is contained in:
parent
fd2dbe7735
commit
da0728d390
4 changed files with 80 additions and 31 deletions
|
|
@ -2,6 +2,7 @@ package cn.super12138.todo.ui.navigation
|
|||
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.SharedTransitionLayout
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
|
|
@ -22,28 +23,9 @@ import cn.super12138.todo.ui.pages.settings.SettingsMain
|
|||
import cn.super12138.todo.ui.pages.tasks.TasksPage
|
||||
import cn.super12138.todo.ui.theme.fadeThrough
|
||||
import cn.super12138.todo.ui.theme.materialSharedAxisX
|
||||
import cn.super12138.todo.ui.theme.veilFade
|
||||
import cn.super12138.todo.ui.viewmodels.MainViewModel
|
||||
|
||||
|
||||
private const val INITIAL_OFFSET_FACTOR = 0.10f
|
||||
|
||||
private fun settingsTransition() = NavDisplay.transitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() },
|
||||
targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() }
|
||||
)
|
||||
} + NavDisplay.popTransitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() },
|
||||
targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }
|
||||
)
|
||||
} + NavDisplay.predictivePopTransitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() },
|
||||
targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
fun TopNavigation(
|
||||
|
|
@ -55,7 +37,33 @@ fun TopNavigation(
|
|||
backStack.removeLast()
|
||||
}
|
||||
|
||||
// val veilColor = MaterialTheme.colorScheme.surfaceDim
|
||||
val veilColor = MaterialTheme.colorScheme.surfaceDim
|
||||
fun editorTransition() = NavDisplay.transitionSpec {
|
||||
veilFade(veilColor)
|
||||
} + NavDisplay.popTransitionSpec {
|
||||
veilFade(veilColor)
|
||||
} + NavDisplay.predictivePopTransitionSpec {
|
||||
veilFade(veilColor)
|
||||
}
|
||||
|
||||
val initialOffestFactor = 0.10f
|
||||
fun settingsTransition() = NavDisplay.transitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { (it * initialOffestFactor).toInt() },
|
||||
targetOffsetX = { -(it * initialOffestFactor).toInt() }
|
||||
)
|
||||
} + NavDisplay.popTransitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { -(it * initialOffestFactor).toInt() },
|
||||
targetOffsetX = { (it * initialOffestFactor).toInt() }
|
||||
)
|
||||
} + NavDisplay.predictivePopTransitionSpec {
|
||||
materialSharedAxisX(
|
||||
initialOffsetX = { -(it * initialOffestFactor).toInt() },
|
||||
targetOffsetX = { (it * initialOffestFactor).toInt() }
|
||||
)
|
||||
}
|
||||
|
||||
SharedTransitionLayout {
|
||||
NavDisplay(
|
||||
backStack = backStack.backStack,
|
||||
|
|
@ -88,7 +96,7 @@ fun TopNavigation(
|
|||
)
|
||||
}
|
||||
|
||||
entry<TodoScreen.Editor.Add> {
|
||||
entry<TodoScreen.Editor.Add>(metadata = editorTransition()) {
|
||||
TodoAddPage(
|
||||
onSave = {
|
||||
viewModel.addTodo(it)
|
||||
|
|
@ -98,7 +106,7 @@ fun TopNavigation(
|
|||
)
|
||||
}
|
||||
|
||||
entry<TodoScreen.Editor.Edit> { editorArgs ->
|
||||
entry<TodoScreen.Editor.Edit>(metadata = editorTransition()) { editorArgs ->
|
||||
TodoEditPage(
|
||||
toDo = editorArgs.toDo,
|
||||
onSave = {
|
||||
|
|
|
|||
|
|
@ -53,10 +53,13 @@ fun SharedTransitionScope.TodoAddPage(
|
|||
onNavigateUp: () -> Unit
|
||||
) = TodoEditorPage(
|
||||
toDo = null,
|
||||
modifier = modifier.sharedBounds(
|
||||
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
|
||||
animatedVisibilityScope = LocalNavAnimatedContentScope.current
|
||||
),
|
||||
modifier = modifier
|
||||
.sharedBounds(
|
||||
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
|
||||
animatedVisibilityScope = LocalNavAnimatedContentScope.current,
|
||||
resizeMode = SharedTransitionScope.ResizeMode.RemeasureToBounds
|
||||
)
|
||||
.skipToLookaheadSize(), // 这个修饰符必须放后面
|
||||
onSave = onSave,
|
||||
onDelete = {},
|
||||
onNavigateUp = onNavigateUp
|
||||
|
|
@ -76,13 +79,14 @@ fun SharedTransitionScope.TodoEditPage(
|
|||
animatedVisibilityScope = LocalNavAnimatedContentScope.current,
|
||||
resizeMode = SharedTransitionScope.ResizeMode.RemeasureToBounds
|
||||
),
|
||||
//TODO: 没想好加不加 .skipToLookaheadSize(),
|
||||
onSave = onSave,
|
||||
onDelete = onDelete,
|
||||
onNavigateUp = onNavigateUp
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun TodoEditorPage(
|
||||
fun SharedTransitionScope.TodoEditorPage(
|
||||
modifier: Modifier = Modifier,
|
||||
toDo: TodoEntity? = null,
|
||||
onSave: (TodoEntity) -> Unit,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.navigation3.ui.LocalNavAnimatedContentScope
|
||||
import cn.super12138.todo.R
|
||||
import cn.super12138.todo.constants.Constants
|
||||
|
|
@ -87,7 +86,8 @@ fun SharedTransitionScope.TasksPage(
|
|||
modifier = Modifier
|
||||
.sharedBounds(
|
||||
sharedContentState = rememberSharedContentState(key = Constants.KEY_TODO_FAB_TRANSITION),
|
||||
animatedVisibilityScope = animatedVisibilityScope
|
||||
animatedVisibilityScope = animatedVisibilityScope,
|
||||
resizeMode = SharedTransitionScope.ResizeMode.RemeasureToBounds
|
||||
)
|
||||
.animateFloatingActionButton(
|
||||
visible = !inSelectedMode,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package cn.super12138.todo.ui.theme
|
|||
import androidx.compose.animation.ContentTransform
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.core.FastOutLinearInEasing
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||
|
|
@ -12,6 +13,9 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.animation.unveilIn
|
||||
import androidx.compose.animation.veilOut
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* 来自:https://github.com/Ashinch/ReadYou/blob/main/app/src/main/java/me/ash/reader/ui/motion/MaterialSharedAxis.kt
|
||||
|
|
@ -114,4 +118,37 @@ fun fadeThroughOut(
|
|||
durationMillis = durationMillis,
|
||||
easing = FastOutLinearInEasing
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fun veilFade(
|
||||
initialColor: Color,
|
||||
durationMillis: Int = 200
|
||||
): ContentTransform = ContentTransform(
|
||||
veilFadeIn(
|
||||
initialColor = initialColor,
|
||||
durationMillis = durationMillis
|
||||
),
|
||||
veilFadeOut(
|
||||
initialColor = initialColor,
|
||||
durationMillis = durationMillis
|
||||
)
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
fun veilFadeIn(
|
||||
initialColor: Color,
|
||||
durationMillis: Int = DefaultMotionDuration,
|
||||
): EnterTransition =
|
||||
fadeIn(
|
||||
) + unveilIn(
|
||||
initialColor = initialColor
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
fun veilFadeOut(
|
||||
initialColor: Color,
|
||||
durationMillis: Int = DefaultMotionDuration,
|
||||
): ExitTransition =
|
||||
fadeOut() + veilOut(
|
||||
targetColor = initialColor
|
||||
)
|
||||
Loading…
Reference in a new issue