fix: 预测性返回兼容性、跟手感与防重入
- 添加 BackHandler 降级,确保 OPPO/ColorOS 等设备基本返回可用 - handleBack 加 isHandlingBack 防重入,避免双 handler 触发 - 完成动画改用 spring 替代 tween,根据手势释放位置自然调速 - dismiss/reveal 变换使用二次缓动(progress²),小幅滑动更柔和跟手
This commit is contained in:
parent
4219527428
commit
6542362f6f
@ -1,6 +1,7 @@
|
|||||||
package plus.rua.project
|
package plus.rua.project
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.navigationevent.NavigationEventInfo
|
import androidx.navigationevent.NavigationEventInfo
|
||||||
@ -40,4 +41,9 @@ actual fun PredictiveBackHandler(
|
|||||||
onProgress(ts.latestEvent.progress)
|
onProgress(ts.latestEvent.progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 降级:部分设备(如 OPPO/ColorOS)不通过 OnBackInvokedCallback 分发返回事件
|
||||||
|
BackHandler(enabled = enabled) {
|
||||||
|
onBack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,13 +35,15 @@ private enum class Screen { Main, About, Licenses }
|
|||||||
|
|
||||||
/** 返回手势动画:顶层页面滑出 + 淡出 + 缩小 + 圆角阴影 */
|
/** 返回手势动画:顶层页面滑出 + 淡出 + 缩小 + 圆角阴影 */
|
||||||
private fun GraphicsLayerScope.applyDismissTransform(progress: Float) {
|
private fun GraphicsLayerScope.applyDismissTransform(progress: Float) {
|
||||||
translationX = progress * size.width * 0.5f
|
// 二次缓动:小幅手势产生更柔和的视觉变化,大幅手势仍达到完整效果
|
||||||
scaleX = 1f - progress * 0.08f
|
val p = progress * progress
|
||||||
scaleY = 1f - progress * 0.08f
|
translationX = p * size.width * 0.5f
|
||||||
alpha = 1f - progress
|
scaleX = 1f - p * 0.08f
|
||||||
shadowElevation = 32.dp.toPx() * progress
|
scaleY = 1f - p * 0.08f
|
||||||
shape = RoundedCornerShape(28.dp * progress)
|
alpha = 1f - p
|
||||||
clip = progress > 0.01f
|
shadowElevation = 32.dp.toPx() * p
|
||||||
|
shape = RoundedCornerShape(28.dp * p)
|
||||||
|
clip = p > 0.01f
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 底层页面缩放:随返回进度从 baseScale 放大到 1.0 */
|
/** 底层页面缩放:随返回进度从 baseScale 放大到 1.0 */
|
||||||
@ -50,7 +52,8 @@ private fun GraphicsLayerScope.applyRevealTransform(
|
|||||||
forwardProgress: Float,
|
forwardProgress: Float,
|
||||||
isForwardAnimating: Boolean
|
isForwardAnimating: Boolean
|
||||||
) {
|
) {
|
||||||
val baseScale = 0.92f + 0.08f * progress
|
val p = progress * progress
|
||||||
|
val baseScale = 0.92f + 0.08f * p
|
||||||
val scale = if (isForwardAnimating) lerp(1f, baseScale, forwardProgress) else baseScale
|
val scale = if (isForwardAnimating) lerp(1f, baseScale, forwardProgress) else baseScale
|
||||||
scaleX = scale
|
scaleX = scale
|
||||||
scaleY = scale
|
scaleY = scale
|
||||||
@ -85,17 +88,21 @@ fun App() {
|
|||||||
var forwardTarget by remember { mutableStateOf<Screen?>(null) }
|
var forwardTarget by remember { mutableStateOf<Screen?>(null) }
|
||||||
val forwardProgress = remember { Animatable(1f) }
|
val forwardProgress = remember { Animatable(1f) }
|
||||||
|
|
||||||
val handleBack: () -> Unit = {
|
var isHandlingBack by remember { mutableStateOf(false) }
|
||||||
|
val handleBack: () -> Unit = lambda@{
|
||||||
|
if (isHandlingBack) return@lambda
|
||||||
|
isHandlingBack = true
|
||||||
scope.launch {
|
scope.launch {
|
||||||
backAnimProgress.snapTo(backProgress)
|
backAnimProgress.snapTo(backProgress)
|
||||||
backProgress = 0f
|
backProgress = 0f
|
||||||
backAnimProgress.animateTo(1f, tween(250, easing = FastOutSlowInEasing))
|
backAnimProgress.animateTo(1f, spring(stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy))
|
||||||
currentScreen = when (currentScreen) {
|
currentScreen = when (currentScreen) {
|
||||||
Screen.About -> Screen.Main
|
Screen.About -> Screen.Main
|
||||||
Screen.Licenses -> Screen.About
|
Screen.Licenses -> Screen.About
|
||||||
else -> currentScreen
|
else -> currentScreen
|
||||||
}
|
}
|
||||||
backAnimProgress.animateTo(0f, tween(100, easing = FastOutSlowInEasing))
|
backAnimProgress.animateTo(0f, spring(stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy))
|
||||||
|
isHandlingBack = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +193,7 @@ fun App() {
|
|||||||
// 预测性返回手势
|
// 预测性返回手势
|
||||||
if (currentScreen != Screen.Main) {
|
if (currentScreen != Screen.Main) {
|
||||||
PredictiveBackHandler(
|
PredictiveBackHandler(
|
||||||
enabled = !backAnimProgress.isRunning && forwardTarget == null,
|
enabled = !backAnimProgress.isRunning && !isHandlingBack && forwardTarget == null,
|
||||||
onProgress = { backProgress = it },
|
onProgress = { backProgress = it },
|
||||||
onBack = handleBack,
|
onBack = handleBack,
|
||||||
onCancel = handleCancel
|
onCancel = handleCancel
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user