diff --git a/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/AccelerateEasing.kt b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/AccelerateEasing.kt new file mode 100644 index 00000000..24869e06 --- /dev/null +++ b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/AccelerateEasing.kt @@ -0,0 +1,28 @@ +package top.yukonga.miuix.kmp.anim + +import androidx.compose.animation.core.Easing +import androidx.compose.runtime.Immutable +import kotlin.math.pow + +/** + * This is equivalent to the Android [AccelerateInterpolator](https://cs.android.com/search?q=file:androidx/core/animation/AccelerateInterpolator.java+class:androidx.core.animation.AccelerateInterpolator) + * + * @param factor Degree to which the animation should be eased. Setting + * factor to 1.0f produces a y=x^2 parabola. Increasing factor above + * 1.0f exaggerates the ease-in effect (i.e., it starts even + * slower and ends evens faster) + */ +@Immutable +class AccelerateEasing( + private val factor: Float = 1.0f +) : Easing { + private val doubleFactor: Float = 2 * factor + + override fun transform(fraction: Float): Float { + return if (factor == 1.0f) { + fraction * fraction + } else { + fraction.pow(doubleFactor) + } + } +} \ No newline at end of file diff --git a/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/DecelerateEasing.kt b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/DecelerateEasing.kt new file mode 100644 index 00000000..39435cdd --- /dev/null +++ b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/anim/DecelerateEasing.kt @@ -0,0 +1,27 @@ + + +package top.yukonga.miuix.kmp.anim + +import androidx.compose.animation.core.Easing +import androidx.compose.runtime.Immutable +import kotlin.math.pow + +/** + * This is equivalent to the Android [DecelerateInterpolator](https://cs.android.com/search?q=file:androidx/core/animation/DecelerateInterpolator.java+class:androidx.core.animation.DecelerateInterpolator) + * + * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces + * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the + * ease-out effect (i.e., it starts even faster and ends evens slower) + */ +@Immutable +class DecelerateEasing( + private val factor: Float = 1.0f +) : Easing { + override fun transform(fraction: Float): Float { + return if (factor == 1.0f) { + 1.0f - (1.0f - fraction) * (1.0f - fraction) + } else { + 1.0f - (1.0f - fraction).pow(2 * fraction) + } + } +} \ No newline at end of file diff --git a/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/utils/MiuixPopupUtil.kt b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/utils/MiuixPopupUtil.kt index 578cd02b..975eba2c 100644 --- a/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/utils/MiuixPopupUtil.kt +++ b/miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/utils/MiuixPopupUtil.kt @@ -1,23 +1,28 @@ package top.yukonga.miuix.kmp.utils import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween -import androidx.compose.animation.expandIn import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut -import androidx.compose.animation.shrinkOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import top.yukonga.miuix.kmp.anim.AccelerateEasing +import top.yukonga.miuix.kmp.anim.DecelerateEasing import top.yukonga.miuix.kmp.basic.Box import top.yukonga.miuix.kmp.basic.Scaffold import top.yukonga.miuix.kmp.theme.MiuixTheme @@ -90,11 +95,16 @@ class MiuixPopupUtil { */ @Composable fun MiuixPopupHost() { + val density = LocalDensity.current + val getWindowSize by rememberUpdatedState(getWindowSize()) + val windowWidth by rememberUpdatedState(getWindowSize.width.dp / density.density) + val windowHeight by rememberUpdatedState(getWindowSize.height.dp / density.density) + val largeScreen by rememberUpdatedState { derivedStateOf { (windowHeight >= 480.dp && windowWidth >= 840.dp) } } AnimatedVisibility( visible = isDialogShowing.value || isPopupShowing.value, modifier = Modifier.zIndex(1f).fillMaxSize(), - enter = fadeIn(animationSpec = tween(500)), - exit = fadeOut(animationSpec = tween(500)) + enter = fadeIn(animationSpec = tween(300, easing = DecelerateEasing(1.5f))), + exit = fadeOut(animationSpec = tween(250, easing = DecelerateEasing(1.5f))) ) { Box( modifier = Modifier @@ -105,20 +115,32 @@ class MiuixPopupUtil { AnimatedVisibility( visible = isDialogShowing.value, modifier = Modifier.zIndex(2f).fillMaxSize(), - enter = slideInVertically( - initialOffsetY = { fullHeight -> fullHeight }, - animationSpec = tween( - durationMillis = 500, - easing = CubicBezierEasing(0f, 1f, 0.36f, 1f) + enter = if (largeScreen.invoke().value) { + fadeIn( + animationSpec = spring(0.9f, 900f) + ) + scaleIn( + initialScale = 0.8f, + animationSpec = spring(0.73f, 900f) ) - ), - exit = slideOutVertically( - targetOffsetY = { fullHeight -> fullHeight }, - animationSpec = tween( - durationMillis = 300, - easing = CubicBezierEasing(1f, 0f, 0.64f, 0f) + } else { + slideInVertically( + initialOffsetY = { fullHeight -> fullHeight }, + animationSpec = spring(0.92f, 500f) ) - ) + }, + exit = if (largeScreen.invoke().value) { + fadeOut( + animationSpec = tween(200, easing = DecelerateEasing(1.5f)) + ) + scaleOut( + targetScale = 0.8f, + animationSpec = tween(200, easing = DecelerateEasing(1.5f)) + ) + } else { + slideOutVertically( + targetOffsetY = { fullHeight -> fullHeight }, + animationSpec = tween(200, easing = DecelerateEasing(1.5f)) + ) + } ) { Box( modifier = Modifier.fillMaxSize() @@ -140,14 +162,16 @@ class MiuixPopupUtil { visible = isPopupShowing.value, modifier = Modifier.zIndex(2f).fillMaxSize(), enter = fadeIn( - animationSpec = tween(150) + animationSpec = tween(150, easing = DecelerateEasing(1.5f)) ) + scaleIn( - animationSpec = tween(150), initialScale = 0.9f + initialScale = 0.8f, + animationSpec = tween(150, easing = DecelerateEasing(1.5f)) ), exit = fadeOut( - animationSpec = tween(150) + animationSpec = tween(150, easing = AccelerateEasing(3.0f)) ) + scaleOut( - animationSpec = tween(150), targetScale = 0.9f + targetScale = 0.8f, + animationSpec = tween(150, easing = AccelerateEasing(3.0f)) ) ) { Box(