feat: 迁移 NavigationBackHandler + 替换应用图标

- 将 PredictiveBackHandler 迁移到 NavigationBackHandler (navigationevent-compose 1.0.1)
- 添加 org.jetbrains.androidx.navigationevent:navigationevent-compose 依赖
- 提取 applyDismissTransform/applyRevealTransform/applyEnterTransform 辅助函数
- 替换所有密度的启动图标和关于页图标
- 移除旧的自适应图标 XML 配置
This commit is contained in:
meyou 2026-05-19 22:24:26 +08:00
parent bde922080a
commit bde143a25b
No known key found for this signature in database
20 changed files with 66 additions and 270 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -16,6 +16,7 @@ material3 = "1.10.0-alpha05"
kotlinx-datetime = "0.8.0"
tyme4kt = "1.4.5"
sketch = "4.4.0"
navigationevent = "1.0.1"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
@ -34,6 +35,7 @@ tyme4kt = { module = "cn.6tail:tyme4kt", version.ref = "tyme4kt" }
sketch-compose = { module = "io.github.panpf.sketch4:sketch-compose", version.ref = "sketch" }
sketch-animated-gif = { module = "io.github.panpf.sketch4:sketch-animated-gif", version.ref = "sketch" }
sketch-compose-resources = { module = "io.github.panpf.sketch4:sketch-compose-resources", version.ref = "sketch" }
navigationevent-compose = { module = "org.jetbrains.androidx.navigationevent:navigationevent-compose", version.ref = "navigationevent" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }

View File

@ -49,6 +49,7 @@ kotlin {
implementation(libs.sketch.compose)
implementation(libs.sketch.animated.gif)
implementation(libs.sketch.compose.resources)
implementation(libs.navigationevent.compose)
}
commonTest.dependencies {
implementation(libs.kotlin.test)

View File

@ -2,8 +2,11 @@ package plus.rua.project
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.CancellationException
import androidx.compose.runtime.LaunchedEffect
import androidx.navigationevent.NavigationEventInfo
import androidx.navigationevent.NavigationEventTransitionState
import androidx.navigationevent.compose.NavigationBackHandler
import androidx.navigationevent.compose.rememberNavigationEventState
class AndroidPlatform : Platform {
override val name: String = "Android ${Build.VERSION.SDK_INT}"
@ -22,19 +25,19 @@ actual fun PredictiveBackHandler(
onBack: () -> Unit,
onCancel: () -> Unit
) {
if (Build.VERSION.SDK_INT >= 34) {
rememberCoroutineScope()
androidx.activity.compose.PredictiveBackHandler(enabled) { progress ->
try {
progress.collect { backEvent ->
onProgress(backEvent.progress)
}
onBack()
} catch (e: CancellationException) {
onCancel()
}
val navState = rememberNavigationEventState(NavigationEventInfo.None)
NavigationBackHandler(
state = navState,
isBackEnabled = enabled,
onBackCancelled = onCancel,
onBackCompleted = onBack
)
LaunchedEffect(navState.transitionState) {
val ts = navState.transitionState
if (ts is NavigationEventTransitionState.InProgress) {
onProgress(ts.latestEvent.progress)
}
} else {
androidx.activity.compose.BackHandler(enabled = enabled, onBack = onBack)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -21,6 +21,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@ -32,6 +33,35 @@ import plus.rua.project.ui.lerp
private enum class Screen { Main, About, Licenses }
/** 返回手势动画:顶层页面滑出 + 淡出 + 缩小 + 圆角阴影 */
private fun GraphicsLayerScope.applyDismissTransform(progress: Float) {
translationX = progress * size.width * 0.5f
scaleX = 1f - progress * 0.08f
scaleY = 1f - progress * 0.08f
alpha = 1f - progress * 0.8f
shadowElevation = 32.dp.toPx() * progress
shape = RoundedCornerShape(28.dp * progress)
clip = progress > 0.01f
}
/** 底层页面缩放:随返回进度从 baseScale 放大到 1.0 */
private fun GraphicsLayerScope.applyRevealTransform(
progress: Float,
forwardProgress: Float,
isForwardAnimating: Boolean
) {
val baseScale = 0.92f + 0.08f * progress
val scale = if (isForwardAnimating) lerp(1f, baseScale, forwardProgress) else baseScale
scaleX = scale
scaleY = scale
}
/** 前向导航动画:新页面从右侧滑入 */
private fun GraphicsLayerScope.applyEnterTransform(progress: Float) {
translationX = (1f - progress) * size.width
alpha = progress
}
/**
* 应用入口 Composable根据系统主题切换明暗 ColorScheme 并管理页面导航
*
@ -59,7 +89,7 @@ fun App() {
scope.launch {
backAnimProgress.snapTo(backProgress)
backProgress = 0f
backAnimProgress.animateTo(1f, tween(200, easing = FastOutSlowInEasing))
backAnimProgress.animateTo(1f, tween(250, easing = FastOutSlowInEasing))
currentScreen = when (currentScreen) {
Screen.About -> Screen.Main
Screen.Licenses -> Screen.About
@ -96,14 +126,11 @@ fun App() {
CalendarMonthView(
modifier = Modifier.graphicsLayer {
if (currentScreen != Screen.Main) {
val baseScale = 0.92f + 0.08f * effectiveBackProgress
val scale = if (forwardTarget != null) {
lerp(1f, baseScale, forwardProgress.value)
} else {
baseScale
}
scaleX = scale
scaleY = scale
applyRevealTransform(
effectiveBackProgress,
forwardProgress.value,
forwardTarget != null
)
}
},
onNavigateToAbout = { navigateTo(Screen.About) }
@ -120,34 +147,18 @@ fun App() {
},
modifier = Modifier.graphicsLayer {
when (currentScreen) {
Screen.Licenses -> {
val baseScale = 0.92f + 0.08f * effectiveBackProgress
val scale = if (forwardTarget == Screen.Licenses) {
lerp(1f, baseScale, forwardProgress.value)
} else {
baseScale
}
scaleX = scale
scaleY = scale
}
Screen.Licenses -> applyRevealTransform(
effectiveBackProgress,
forwardProgress.value,
forwardTarget == Screen.Licenses
)
Screen.About -> {
val bp = effectiveBackProgress
val fp = forwardProgress.value
when {
bp > 0.001f -> {
translationX = bp * size.width * 0.3f
scaleX = 1f - bp * 0.05f
scaleY = 1f - bp * 0.05f
shadowElevation = 32.dp.toPx() * bp
shape = RoundedCornerShape(28.dp * bp)
clip = bp > 0.01f
}
fp < 0.999f && forwardTarget == Screen.About -> {
translationX = (1f - fp) * size.width
alpha = fp
}
bp > 0.001f -> applyDismissTransform(bp)
fp < 0.999f && forwardTarget == Screen.About -> applyEnterTransform(fp)
}
}
@ -165,19 +176,8 @@ fun App() {
val bp = effectiveBackProgress
val fp = forwardProgress.value
when {
bp > 0.001f -> {
translationX = bp * size.width * 0.3f
scaleX = 1f - bp * 0.05f
scaleY = 1f - bp * 0.05f
shadowElevation = 32.dp.toPx() * bp
shape = RoundedCornerShape(28.dp * bp)
clip = bp > 0.01f
}
fp < 0.999f && forwardTarget == Screen.Licenses -> {
translationX = (1f - fp) * size.width
alpha = fp
}
bp > 0.001f -> applyDismissTransform(bp)
fp < 0.999f && forwardTarget == Screen.Licenses -> applyEnterTransform(fp)
}
}
)