[jetpack compose] Animatable (feat. AnimationResult)

유민국·2024년 9월 27일

Animatable

public fun Animatable(
    initialValue: Float,
    // Spring.DefaultDisplacementThreshold
    // 기존값으로 아주 작은값(0.01f)로 설정
    // 애니메이션이 목표값에 도달하는 동안 발생할 수 있는 미세한 진동이나 
    // 잔여 움직임을 제거하기 위해 사용
    visibilityThreshold: Float = Spring.DefaultDisplacementThreshold
): Animatable<Float, AnimationVector1D>
@Suppress("NotCloseable")
class Animatable<T, V : AnimationVector>(
    initialValue: T,
    val typeConverter: TwoWayConverter<T, V>,
    // 애니메이션이 완료되었다고 간주되는 값의 오차 범위를 정의
    // 현재 값과 최종 값의 차이가 이 변수보다 작다면 완료되었다고 간주
    private val visibilityThreshold: T? = null,
    val label: String = "Animatable"
)

애니메이션이 가능한 상태 값을 관리(AnimationState통해)하며 그 값이 변경될 때마다 애니메이션 효과를 적용

LaunchedEffect, remember와 같은 상태 관리 및 사이드 이펙트 처리 기능과 결합하여 사용할 수 있다

Animatable객체는 상태를 유지하면서, 특정 목표 값까지 애니메이션을 수행한다

animate*AsState함수 안에 Animatable객체가 포함되어 있으며 간단하게 사용할 경우에는 animate*AsState를 사용하고 만약 세밀한 에니메이션 제어가 필요한 경우 Animatable객체 사용을 고려해보면 될 것 같다.

.
.
.
.
객체를 통해 사용할 변수나 함수들은 다음과 같다

멤버 변수

// Animatable은 AnimationState를 가지고 있다
internal val internalState = AnimationState(
    typeConverter = typeConverter,
    initialValue = initialValue
)
// 애니메이션이 진행되는 동안 실시간으로 업데이트 되는 값
val value: T
    get() = internalState.value
// 애니메이션이 얼마나 빠르게 변화는지를 나타낸다
val velocityVector: V
    get() = internalState.velocityVector
// velocityVector를 T 타입으로 변환한 변화율을 나타낸다
// velocityVector는 벡터 단위, velocity는 T 타입으로 변화율를 반환
val velocity: T
    get() = typeConverter.convertFromVector(velocityVector)
// 애니메이션 진행 여부
var isRunning: Boolean by mutableStateOf(false)
var targetValue: T by mutableStateOf(initialValue)
// 애니메이션 값이 특정 값을 넘지 않도록 제한하는 역할
// 특정 범위 내에서만 애니메이션을 진행하고 싶을 때 사용
var lowerBound: T? = null
var upperBound: T? = null

멤버 함수

애니메이션 시작을 위해 또 다른 애니메이션 함수(animateTo, animateDecay)를 사용하거나 stop, snapTo를 사용한 경우에는 CancellationException을 발생시키며, 이로 인해 호출자의 코루틴에서 모든 후속 작업이 취소된다. 만약 취소될 때 수행할 정리 작업이 있는 경우 애니메이션을 try-catch을 사용하여 처리하는걸 고려해야 한다.
.
애니메이션이 종료되면 속도는 0으로 초기화 된다. 중단 되거나 경계에 도달했을 때의 애니메이션 상태는 반환된 AnimationResult에 저장되며 중단되기 전의 모멘텀을 계속할 필요가 있는 경우 AnimationResult.endState에 있는 속도를 사용하여 새로운 애니메이션을 시작하는 것이 좋다

animateTo : 현재 값에서 지정된 targetValue로 애니메이션

  • 이미 애니메이션이 진행 중인 경우, 진행 중인 애니메이션을 취소하고, 현재 value와 velocity를 이어서 새로운 애니메이션을 시작한다
  • 플링(fling)애니메이션이 끝난 후에 initialVelocity를 설정해야 자연스러운 흐름을 유지할 수 있으며, 대부분 다른 경우는 시각적으로 부자연스러울 수 있다
public final suspend fun animateTo(
    targetValue: T,
    animationSpec: AnimationSpec<T> = defaultSpringSpec,
    initialVelocity: T = velocity,
    block: (Animatable<T, V>.() -> Unit)? = null
): AnimationResult<T, V>

animateDecay : 감쇄 애니메이션(initialVelocity를 기반으로 점점 느려짐)을 시작

  • fling 제스처 후에 자주 사용된다
public final suspend fun animateDecay(
    initialVelocity: T,
    animationSpec: DecayAnimationSpec<T>,
    block: (Animatable<T, V>.() -> Unit)? = null
): AnimationResult<T, V>

snapTo : 애니메이션을 중단하고 값을 즉시 targetValue로 설정

  • 진행 중인 애니메이션을 취소(CancellationException 발생)
  • 만약 경계값(bounds)를 설정한 경우, 경계에 맞게 targetValue가 조정된다. ex) lowerBound = 0인데 -5로 지정한경우 0으로 설정
public final suspend fun snapTo(
    targetValue: T
): Unit

updateBounds: 애니메이션 값 최소값, 최대값 지정(특정 범위를 넘지 않도록 설정)

public final fun updateBounds(
    lowerBound: T? = this.lowerBound,
    upperBound: T? = this.upperBound
): Unit

stop, asState

public final suspend fun stop(): Unit
public final fun asState(): State<T>

AnimationResult

class AnimationResult<T, V : AnimationVector>(
	// 애니메이션이 취소되거나 재설정되기 전 마지막 프레임에서의 애니메이션 상태
    // 중단 시점의 애니메이션 값, 속도, 프레임 시간 등을 캡처하여 
    // 애니메이션이 성공적으로 완료될 때 속도가 재설정되기 전의 상태를 나타낸다
    val endState: AnimationState<T, V>,
    
    // 애니메이션이 종료된 이유를 나타낸다
    // Finished: 애니메이션이 중단 없이 성공적으로 종료될 때
    // BoundReached: 애니메이션이 어느 한 차원에서 lowerBound 또는
    // Animatable.upperBound에 도달하면,
    // BoundReached를 종료 이유로 하여 끝낸다
    val endReason: AnimationEndReason
)
profile
안녕하세요 😊

0개의 댓글