nueijeel

[Android] Object Animator를 활용한 간단한 애니메이션 구현하기 본문

Android/공부

[Android] Object Animator를 활용한 간단한 애니메이션 구현하기

nueijeel 2023. 11. 26. 10:18

 

프로젝트를 진행하다가 fab 클릭 시 나타나는 메뉴에 효과를 주고싶어 애니메이션 구현하는 방법을 공부해보았다. 실제로 안드로이드 개발자들이 실무에서 직접 사용하는지는 모르겠지만, 여러 효과들을 배치함으로써 더 풍부한 ux를 제공하는 데 도움이 될 것 같아 나중에도 미니 프로젝트에 사용할 수 있게 내용을 정리해두려고 한다.

 


 

안드로이드에서는 애니메이션을 위해 Animator 클래스를 지원한다.

Animator 클래스는 기본적인 애니메이션을 제공하는 클래스들의 슈퍼 클래스로, 기본적으로 애니메이션을 시작하고 종료하는 역할을 한다.

 

Animator 클래스의 대표적인 하위 클래스

1. AnimatorSet
: 지정된 순서대로 일련의 Animator 객체를 재생하는 데 사용

2. ValueAnimator
: 계산된 값들을 애니메이션화하여 대상 객체에 설정하는 데 사용

3. ObjectAnimator
: ValueAnimator의 하위 클래스로, 대상 객체의 특정한 속성을 애니메이션화 할 때 사용

 

 

fab 클릭 시 나오는 메뉴는 5개의 뷰로 구성되어 있기 때문에 ObjectAnimator가 목적에 가장 적합한 animator라고 생각했다.

 

 

Object Animator는 코드로도 정의할 수 있고, 리소스 파일로도 적용할 수 있다.

또, API 23 이후부터는 PropertyValuesHolder를 리소스 파일 내에서 사용해 더 복잡한 애니메이션을 정의할 수 있게 됐다.

 

PropertyValuesHolder는 하나의 객체에 대해 여러 애니메이션 속성값을 동시에 다룰 수 있게 해주는 클래스로, ValueAnimator와 ObjectAnimator로 애니메이션을 생성할 때 사용할 수 있다.

 

 

Object Animator의 속성

<set
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["restart" | "reverse"]
        android:valueType=["intType" | "floatType"]
        android:interpolator="@android:interpolator/accelerate_decelerate"/>

</set>

 

  • ordering
    • together : set에 있는 애니메이션을 동시에 재생 (default)
    • sequentially : set에 있는 애니메이션을 순차 재생
  • propertyName : 객체에서 animate 시킬 속성을 지정
    • alpha 투명도
    • rotationX 위아래로 회전, rotationY 양옆 회전, rotation 시계방향 반시계방향
    • translationX x축이동, translationY y축 이동
    • backgroundColor 배경색
    • textColor 텍스트 색상
    • scaleX x방향 늘리기, scaleY y방향 늘리기                  
  • duration : 애니메이션 실행 시간 ms단위
  • valueFrom : propertyName에서 지정한 속성값의 시작값
  • valueTo : propertyName에서 지정한 속성값의 종료값
  • valueType : animate될 값의 타입을 지정
  • startOffset : 애니메이션의 시작 시간을 지정
  • repeatMode : 반복 모드.
    • restart : 처음 상태로 다시 돌아가서 반복 
    • reverse : 종료된 상태에서 반복
  • repeatCount : 반복 횟수, -1은 무한 반복
  • interpolator : 애니메이션 진행 속도에 대한 옵션
    • linear_interpolator : 일정한 속도로 진행
    • accelerate_interpolator : 느리다가 빨라짐
    • anticipate_interpolator : 시작시 조금 당겼다가 시작
    • bounce_interpolator : 마지막에 약간 통통 튐
    • cycle_interpolator : 진행이 끝나면 다시 역재생
    • decelerate_interpolator : 빠르다가 느려짐
    • overshoot_interpolator : 약간 더 진행되었다가 돌아옴

    

위와 같이 xml로 object animator를 작성했을때 해당 애니메이션이 적용될 target 객체를 리소스 파일 상에서 지정할 수 없기 때문에, 코드에서 setTarget() 함수를 통해 객체를 지정해준다.

 

해당 xml 구조로 작성된 애니메이션을 객체에 적용하면 하나의 애니메이션만 수행이 되지만, 해당 객체에 동시에 여러 애니메이션을 적용할 수도 있다. object animator를 여러개 생성하고 set의 ordering 속성을 지정하는 방법이나 앞서 설명했던 PropertyValuesHolder를 이용하는 방법이다.

 

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:interpolator="@android:anim/linear_interpolator">

    <propertyValuesHolder
        android:propertyName="translationX"
        android:valueFrom="0dp"
        android:valueTo="-70dp"
        android:valueType="floatType"/>
    <propertyValuesHolder
        android:propertyName="translationY"
        android:valueFrom="0dp"
        android:valueTo="-70dp"
        android:valueType="floatType"/>

</objectAnimator>

 

PropertyValuesHolder를 사용해 한 Object Animator에 두 가지 애니메이션을 한꺼번에 지정해보았다.

translationX, translationY 속성 값을 지정해 시작 위치로부터 x, y축으로 70씩 이동하도록 하였다.

 

val animation = AnimatorInflater.loadAnimator(this, R.animator.translation_xy_animator).apply{
    setTarget(textView1)
    start()
}

 

앞서 작성한 xml 리소스를 loadAnimator에 넘겨주고 setTarget 함수를 통해 객체와 연결해주면 해당 뷰에 애니메이션이 적용된다. 

 

이렇게 하나의 뷰에 대해 하나 이상의 애니메이션을 적용하는 방법을 살펴보았다.

 

 

 

여러개의 뷰에 대해 동시에 애니메이션을 실행시키는 경우 Animator Set을 이용할 수 있다.

 

우선 각 뷰에 적용되어야 하는 Object Animator를 전부 생성해주고, 코드로 애니메이션들을 묶어준다.

 

val animation1 = AnimatorInflater.loadAnimator(this@MainActivity, R.animator.menu_dog_food_animator).apply {
    setTarget(menuDogFoodAdd)
}
val animation2 = AnimatorInflater.loadAnimator(this@MainActivity, R.animator.menu_feces_animator).apply {
    setTarget(menuFecesAdd)
}
val animation3 = AnimatorInflater.loadAnimator(this@MainActivity, R.animator.menu_symptom_animator).apply {
    setTarget(menuSymptomAdd)
}
val animation4 = AnimatorInflater.loadAnimator(this@MainActivity, R.animator.menu_nutrition_animator).apply {
    setTarget(menuNutritionAdd)
}
val animation5 = AnimatorInflater.loadAnimator(this@MainActivity, R.animator.menu_weight_animator).apply {
    setTarget(menuWeightEdit)
}

val animationSet = AnimatorSet().apply {
    play(animation1).with(animation2).with(animation3).with(animation4).with(animation5)
}

 

모든 애니메이션이 동시에 수행되게 하기위해 play 메서드와 with 메서드로 애니메이션 그룹을 지정하였다.

이외에도 after 함수를 통해 애니메이션을 지연시키거나, before 함수를 통해 애니메이션의 실행 순서를 지정할 수도 있다.

 

fabMain.setOnClickListener {
    AnimatorSet().apply {
        play(animationSet)
        start()
    }
}

 

생성한 animation Set을 원하는 위치에서 실행 (start)하면 해당 animation set이 수행된다.

 

 

728x90