TP-82542 | Naman Khurmi | Addition of keyFrame spec for animation in Uitron (#559)

This commit is contained in:
Naman Khurmi
2024-09-17 15:11:58 +05:30
committed by GitHub
parent 3c6010e0dc
commit d218da1e6c
5 changed files with 144 additions and 37 deletions

View File

@@ -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
}
/**

View File

@@ -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>

View File

@@ -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
) {

View File

@@ -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(

View File

@@ -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 arent 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())
}
}
}
}
}