TP-82542 | Naman Khurmi | Addition of keyFrame spec for animation in Uitron (#559)
This commit is contained in:
@@ -87,12 +87,13 @@ fun <T> animatedSpec(animationSpec: AnimationSpec? = null): FiniteAnimationSpec<
|
||||
*
|
||||
* @return Easing - The easing
|
||||
*/
|
||||
fun EasingType.toEasing(): Easing =
|
||||
fun EasingType?.toEasing(): Easing =
|
||||
when (this) {
|
||||
EasingType.FastOutSlowInEasing -> FastOutSlowInEasing
|
||||
EasingType.LinearOutSlowInEasing -> LinearOutSlowInEasing
|
||||
EasingType.FastOutLinearInEasing -> FastOutLinearInEasing
|
||||
EasingType.LinearEasing -> LinearEasing
|
||||
else -> LinearEasing
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.navi.uitron.model.animations.animateColorSet
|
||||
import com.navi.uitron.model.animations.animateFloatSet
|
||||
import com.navi.uitron.model.animations.animateIntSet
|
||||
import com.navi.uitron.model.animations.animateOffsetSet
|
||||
import com.navi.uitron.model.animations.getKeyFrames
|
||||
import com.navi.uitron.model.ui.AnimationState
|
||||
import com.navi.uitron.model.ui.BaseProperty
|
||||
import com.navi.uitron.model.ui.TextProperty
|
||||
@@ -57,8 +58,8 @@ fun createAnimationProperty(
|
||||
}
|
||||
}
|
||||
|
||||
animatePropertiesList?.let {
|
||||
it.forEach { propertyAnimator ->
|
||||
animatePropertiesList?.let { list ->
|
||||
list.forEach { propertyAnimator ->
|
||||
when (val propertyName = propertyAnimator?.propertyName) {
|
||||
in animateFloatSet -> {
|
||||
val floatData = propertyAnimator as? FloatInterpolator
|
||||
@@ -69,7 +70,8 @@ fun createAnimationProperty(
|
||||
targetToInitAnimSpec = propertyAnimator.targetToInitAnimSpec,
|
||||
label = propertyName?.name,
|
||||
targetValue = floatData.targetFloatValue ?: 0f,
|
||||
defaultValue = floatData.initialFloatValue ?: 0f
|
||||
defaultValue = floatData.initialFloatValue ?: 0f,
|
||||
keyFrames = getKeyFrames(propertyAnimator.floatKeyFrames) { it }
|
||||
)
|
||||
SetFloatProperty(
|
||||
propertyName = propertyName,
|
||||
@@ -95,7 +97,11 @@ fun createAnimationProperty(
|
||||
Offset(
|
||||
offsetData.initialOffset?.x ?: 0f,
|
||||
offsetData.initialOffset?.y ?: 0f
|
||||
)
|
||||
),
|
||||
keyFrames =
|
||||
getKeyFrames(propertyAnimator.offsetKeyFrames) {
|
||||
Offset(it.x ?: 0f, it.y ?: 0f)
|
||||
}
|
||||
)
|
||||
SetOffsetProperty(
|
||||
propertyName = propertyName,
|
||||
@@ -124,7 +130,11 @@ fun createAnimationProperty(
|
||||
?.textColor
|
||||
?.hexToComposeColor ?: Color.Black
|
||||
else -> Color.Transparent
|
||||
}
|
||||
},
|
||||
keyFrames =
|
||||
getKeyFrames(propertyAnimator.colorKeyFrames) {
|
||||
it.hexToComposeColor
|
||||
}
|
||||
)
|
||||
SetColorProperty(
|
||||
propertyName = propertyName,
|
||||
@@ -145,7 +155,8 @@ fun createAnimationProperty(
|
||||
defaultValue =
|
||||
intData.initialIntValue
|
||||
?: (baseProperty as? TextProperty)?.fontSize
|
||||
?: 0
|
||||
?: 0,
|
||||
keyFrames = getKeyFrames(propertyAnimator.intKeyFrames) { it }
|
||||
)
|
||||
SetIntProperty(
|
||||
propertyName = propertyName,
|
||||
@@ -163,7 +174,7 @@ fun createAnimationProperty(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SetFloatProperty(
|
||||
private fun SetFloatProperty(
|
||||
propertyName: AnimateProperty?,
|
||||
animatedProperties: AnimatedProperties,
|
||||
value: State<Float>
|
||||
@@ -185,7 +196,7 @@ fun SetFloatProperty(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SetIntProperty(
|
||||
private fun SetIntProperty(
|
||||
propertyName: AnimateProperty?,
|
||||
animatedProperties: AnimatedProperties,
|
||||
value: State<Int>
|
||||
@@ -197,7 +208,7 @@ fun SetIntProperty(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SetColorProperty(
|
||||
private fun SetColorProperty(
|
||||
propertyName: AnimateProperty?,
|
||||
animatedProperties: AnimatedProperties,
|
||||
value: State<Color>
|
||||
@@ -210,7 +221,7 @@ fun SetColorProperty(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SetOffsetProperty(
|
||||
private fun SetOffsetProperty(
|
||||
propertyName: AnimateProperty?,
|
||||
animatedProperties: AnimatedProperties,
|
||||
value: State<Offset>
|
||||
|
||||
@@ -9,6 +9,7 @@ package com.navi.uitron.helpers.animationHelper
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.KeyframesSpec
|
||||
import androidx.compose.animation.core.Transition
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.animateInt
|
||||
@@ -30,14 +31,16 @@ fun Transition<Boolean>.anFloat(
|
||||
targetToInitAnimSpec: AnimationSpec?,
|
||||
label: String?,
|
||||
targetValue: Float?,
|
||||
defaultValue: Float
|
||||
defaultValue: Float,
|
||||
keyFrames: KeyframesSpec<Float>?
|
||||
): State<Float> {
|
||||
return animateFloat(
|
||||
transitionSpec = {
|
||||
when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
keyFrames
|
||||
?: when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
},
|
||||
label = label ?: FLOAT_ANIMATION
|
||||
) {
|
||||
@@ -55,14 +58,16 @@ fun Transition<Boolean>.anColor(
|
||||
targetToInitAnimSpec: AnimationSpec?,
|
||||
label: String?,
|
||||
targetColor: Color?,
|
||||
initialColor: Color
|
||||
initialColor: Color,
|
||||
keyFrames: KeyframesSpec<Color>?
|
||||
): State<Color> {
|
||||
return animateColor(
|
||||
transitionSpec = {
|
||||
when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
keyFrames
|
||||
?: when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
},
|
||||
label = label ?: COLOR_ANIMATION
|
||||
) {
|
||||
@@ -80,14 +85,16 @@ fun Transition<Boolean>.anInt(
|
||||
targetToInitAnimSpec: AnimationSpec?,
|
||||
label: String?,
|
||||
targetValue: Int?,
|
||||
defaultValue: Int
|
||||
defaultValue: Int,
|
||||
keyFrames: KeyframesSpec<Int>?
|
||||
): State<Int> {
|
||||
return animateInt(
|
||||
transitionSpec = {
|
||||
when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
keyFrames
|
||||
?: when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
},
|
||||
label = label ?: INT_ANIMATION
|
||||
) {
|
||||
@@ -105,14 +112,16 @@ fun Transition<Boolean>.anOffset(
|
||||
targetToInitAnimSpec: AnimationSpec?,
|
||||
label: String?,
|
||||
targetOffset: Offset?,
|
||||
defaultOffset: Offset
|
||||
defaultOffset: Offset,
|
||||
keyFrames: KeyframesSpec<Offset>?
|
||||
): State<Offset> {
|
||||
return animateOffset(
|
||||
transitionSpec = {
|
||||
when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
keyFrames
|
||||
?: when {
|
||||
false isTransitioningTo true -> animatedSpec(initToTargetAnimSpec)
|
||||
else -> animatedSpec(targetToInitAnimSpec)
|
||||
}
|
||||
},
|
||||
label = label ?: OFFSET_ANIMATION
|
||||
) {
|
||||
|
||||
@@ -24,21 +24,29 @@ open class PropertyAnimator(
|
||||
@Parcelize
|
||||
data class FloatInterpolator(
|
||||
var initialFloatValue: Float? = null,
|
||||
var targetFloatValue: Float? = null
|
||||
var targetFloatValue: Float? = null,
|
||||
var floatKeyFrames: AnimationKeyFrames<Float>? = null
|
||||
) : PropertyAnimator()
|
||||
|
||||
@Parcelize
|
||||
data class IntInterpolator(var initialIntValue: Int? = null, var targetIntValue: Int? = null) :
|
||||
PropertyAnimator()
|
||||
data class IntInterpolator(
|
||||
var initialIntValue: Int? = null,
|
||||
var targetIntValue: Int? = null,
|
||||
var intKeyFrames: AnimationKeyFrames<Int>? = null
|
||||
) : PropertyAnimator()
|
||||
|
||||
@Parcelize
|
||||
data class ColorInterpolator(var initialColor: String? = null, var targetColor: String? = null) :
|
||||
PropertyAnimator()
|
||||
data class ColorInterpolator(
|
||||
var initialColor: String? = null,
|
||||
var targetColor: String? = null,
|
||||
var colorKeyFrames: AnimationKeyFrames<String>? = null
|
||||
) : PropertyAnimator()
|
||||
|
||||
@Parcelize
|
||||
data class OffsetInterpolator(
|
||||
var initialOffset: OffSetData? = null,
|
||||
var targetOffset: OffSetData? = null
|
||||
var targetOffset: OffSetData? = null,
|
||||
var offsetKeyFrames: AnimationKeyFrames<OffSetData>? = null
|
||||
) : PropertyAnimator()
|
||||
|
||||
data class AnimatedProperties(
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.uitron.model.animations
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.animation.core.KeyframesSpec
|
||||
import androidx.compose.animation.core.keyframes
|
||||
import com.navi.uitron.helpers.animationHelper.toEasing
|
||||
import com.navi.uitron.utils.DEFAULT_DELAY_MILLIS
|
||||
import com.navi.uitron.utils.DEFAULT_DURATION_MILLIS
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.RawValue
|
||||
|
||||
/**
|
||||
* Holds a bunch of keyframes for an animation.
|
||||
*
|
||||
* @param T The type of value that's changing over time.
|
||||
* @property durationMillis How long the animation runs in milliseconds.
|
||||
* @property delayMillis How long to wait before starting the animation, in milliseconds.
|
||||
* @property keyFrames List of keyframes with values and their timings.
|
||||
*/
|
||||
@Parcelize
|
||||
data class AnimationKeyFrames<T>(
|
||||
var durationMillis: Int = DEFAULT_DURATION_MILLIS,
|
||||
var delayMillis: Int = DEFAULT_DELAY_MILLIS,
|
||||
val keyFrames: List<Frame<T>>
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
* Represents a single keyframe in an animation.
|
||||
*
|
||||
* @param T The type of value this keyframe holds.
|
||||
* @property timeMarker When this keyframe happens, in milliseconds.
|
||||
* @property timeFraction The fraction of the animation's total duration at which this keyframe
|
||||
* occurs. Should be between 0 and 1.
|
||||
* @property frameValue The value at this time.
|
||||
* @property easingType How the value should ease in or out (e.g., fast, slow). Default is linear.
|
||||
*/
|
||||
@Parcelize
|
||||
data class Frame<T>(
|
||||
val timeMarker: Int? = null,
|
||||
val timeFraction: Float? = null,
|
||||
val frameValue: @RawValue T,
|
||||
val easingType: EasingType? = null
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
* Converts a set of keyframes into a `KeyframesSpec` for animations.
|
||||
*
|
||||
* @param T Original value type in the keyframes.
|
||||
* @param R New value type after conversion.
|
||||
* @param keyFrames Keyframes to convert, or `null` if there aren’t any.
|
||||
* @param convert Function to change a value from type `T` to type `R`.
|
||||
* @return A `KeyframesSpec` for `R`, or `null` if there are no keyframes.
|
||||
*/
|
||||
fun <T, R> getKeyFrames(keyFrames: AnimationKeyFrames<T>?, convert: (T) -> R): KeyframesSpec<R>? {
|
||||
return keyFrames?.let {
|
||||
keyframes {
|
||||
durationMillis = it.durationMillis
|
||||
delayMillis = it.delayMillis
|
||||
it.keyFrames.forEach { frame ->
|
||||
frame.timeFraction?.let { fraction ->
|
||||
convert(frame.frameValue)
|
||||
.atFraction(fraction)
|
||||
.using(frame.easingType.toEasing())
|
||||
}
|
||||
?: frame.timeMarker?.let { marker ->
|
||||
convert(frame.frameValue).at(marker).using(frame.easingType.toEasing())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user