feat(ui): predictive back animation for Android 14+

This commit is contained in:
junkfood 2024-11-12 21:55:49 +08:00
parent c691a106d5
commit 2655cb5f43
No known key found for this signature in database
GPG Key ID: 2EA5B648DB112A34
3 changed files with 65 additions and 15 deletions

View File

@ -4,8 +4,10 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" /> android:maxSdkVersion="28" />
<queries> <queries>
<intent> <intent>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -19,6 +21,7 @@
<application <application
android:name=".infrastructure.android.AndroidApp" android:name=".infrastructure.android.AndroidApp"
android:allowBackup="true" android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/read_you" android:label="@string/read_you"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"

View File

@ -8,19 +8,69 @@
package me.ash.reader.ui.ext package me.ash.reader.ui.ext
import android.os.Build
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink import androidx.navigation.NavDeepLink
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import me.ash.reader.ui.motion.EmphasizedAccelerate
import me.ash.reader.ui.motion.EmphasizedDecelerate
import me.ash.reader.ui.motion.materialSharedAxisXIn import me.ash.reader.ui.motion.materialSharedAxisXIn
import me.ash.reader.ui.motion.materialSharedAxisXOut import me.ash.reader.ui.motion.materialSharedAxisXOut
private const val INITIAL_OFFSET_FACTOR = 0.10f private const val INITIAL_OFFSET_FACTOR = 0.10f
private const val INITIAL_SCALE_FACTOR = 0.8f
fun NavGraphBuilder.animatedComposable( fun NavGraphBuilder.animatedComposable(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
usePredictiveBack: Boolean = Build.VERSION.SDK_INT >= 34,
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit,
) {
if (usePredictiveBack) {
animatedComposablePredictiveBack(route, arguments, deepLinks, content)
} else {
animatedComposableLegacy(route, arguments, deepLinks, content)
}
}
fun NavGraphBuilder.animatedComposablePredictiveBack(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit,
) =
composable(
route = route,
arguments = arguments,
deepLinks = deepLinks,
enterTransition = { materialSharedAxisXIn(initialOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }) },
exitTransition = {
materialSharedAxisXOut(targetOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
},
popEnterTransition = {
scaleIn(
animationSpec = tween(durationMillis = 350, easing = EmphasizedDecelerate),
initialScale = INITIAL_SCALE_FACTOR,
) + materialSharedAxisXIn(initialOffsetX = { -(it * INITIAL_OFFSET_FACTOR).toInt() })
},
popExitTransition = {
materialSharedAxisXOut(targetOffsetX = { (it * INITIAL_OFFSET_FACTOR).toInt() }) +
scaleOut(
targetScale = INITIAL_SCALE_FACTOR,
animationSpec = tween(durationMillis = 350, easing = EmphasizedAccelerate),
)
},
content = content,
)
fun NavGraphBuilder.animatedComposableLegacy(
route: String, route: String,
arguments: List<NamedNavArgument> = emptyList(), arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(), deepLinks: List<NavDeepLink> = emptyList(),

View File

@ -204,9 +204,6 @@ fun FeedsPage(
} }
} }
BackHandler(true) {
context.findActivity()?.moveTaskToBack(false)
}
RYScaffold( RYScaffold(
topBarTonalElevation = topBarTonalElevation.value.dp, topBarTonalElevation = topBarTonalElevation.value.dp,