본문 바로가기
Android/애니메이션

[Android] Property Animation, 속성 애니메이션

by 붕어사랑 티스토리 2022. 2. 9.
반응형

https://developer.android.com/guide/topics/graphics/prop-animation

 

속성 애니메이션 개요  |  Android 개발자  |  Android Developers

속성 애니메이션 개요 속성 애니메이션 시스템은 거의 모든 항목을 애니메이션으로 만들 수 있는 강력한 프레임워크입니다. 애니메이션을 정의하여 화면에 그리는지에 관계없이 시간 경과에

developer.android.com

 

프로퍼티 애니메이션, 속성 애니메이션이란?

안드로이드에는 수많은 애니메이션이 있다. 그중 가장 강력한 애니메이션을 뽑자면 당연 프로퍼티 애니메이션이다.

프로퍼티 애니메이션은 거의 모든것을 애니메이션화 시킬 수 있다

 

프로퍼티 애니메이션이란 특정한 값(프로퍼티)가 변화할 때, start값과 end값 사이에 들어가는 애니메이션이다.

 

여기서 말하는 프로퍼티란 객체안에 생성된 변수값을 가리킨다.

이것만 보면 꼭 클래스 객체를 생성해서 애니메이션을 돌려야 할 것 같지만,

실제로는 값에 의해서만 돌아가기 때문에 클래스랑 큰 상관이 없다.

 

중요한건 start value와 end value이다.

 

프로퍼티 애니메이션의 사용법

 

 

  • 애니메이터를 생성하고, start valueend value를 넣어준다
  • Interpolator를 정해준다(선택사항)
  • 애니메이션의 addUpdateListner를 정해준다
  • Duration을 정해준다
  • start 한다

 

여기서 Interpolator란 보간법을 의미하는데, 보간이 뭐냐면 값 사이사이에 새로운 값을 넣어주는것이다.

즉, 뷰의 위치가 0에서 40으로 변했다고 하면 0과 40 사이에 새로운 값을 넣어주는 것 이다.

 

 

addUpdateListner에서는 0에서 40으로 값이 실시간으로 변하는 값을 받아와 준다.

즉 이 값을 통해 원하는 애니메이션 동작을 취하면 되는 것!

 

 

 

 

 

 

 

다음 예제는 textView의 text를 0부터 100까지 증가시키는 애니메이션이다.

 

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.myTextView);

        ValueAnimator animator = ValueAnimator.ofInt(0,100);

        // 값이 빠르게 증가하는 보간법
        animator.setInterpolator(new AccelerateInterpolator());

        animator.addUpdateListener(valueAnimator -> {
            //getAnimatedValue를 통해 애니메이션의 현재 value를 가져올 수 있다
            int currentValue = (int)valueAnimator.getAnimatedValue();
            tv.setText(Integer.toString(currentValue));
        });

        animator.setDuration(3000);
        animator.start();
    }
}

 

 

ValuAnimator.ofInt(0, 100)

값을 0부터 100까지 변화시키겠다는 의미이다.

 

setInerplator()

아까 언급한 보간법을 정해주는 메소드이다. 생략 가능하다

여기서 나는 AccelerateInterpolator라는 보간법을 사용했는데 이는 애니메이션 속도가 점점 가속화 되는 보간법이다.

 

setDuration()

애니메이션의 길이를 정해주는 메소드이다. 단위는 ms이며 기본값은 300ms이다.

 

 

addUpdateListner()

원하는 애니메이션을 작성해야 한다. getAnimatedValue() 메소드를 이용하여

현재 진행중인 애니메이션 값을 가져 온 후, 이를 이용해 원하는 동작을 작성한다

 

 

 

 

 

 

 

 

 

Animator의 종류

앞선 예제에서 animator라는 놈이 나온다. 이놈은 프로퍼티 애니메이션의 핵심 역할을 하며 실제 애니메이션을 만들어주는 녀석이다.

 

이 애니메이터는 다음과 같은 애니메이터들이 있따.

 

 

  • ValueAnimator

애니메이터의 가장 기본이 되는 애니메이터이다. 앞서 배운것 처럼 프로퍼티의 값을 계산해주고 시간에대한 정보도 얻을 수 있고 애니메이션의 값이 바뀔 때 마다 리스너를 달아 줄 수 있고 반복 설정도 해 줄 수 있다.

 

허나 한가지 기억하자

 

프로퍼티의 애니메이션은 두가지의 작업으로 구성되어 있는데

 

1. 애니메이션이 진행될 때 value값을 계산해주는 작업

2. 계산된 value값을 객체이 set하여 진짜로 프로퍼티 값이 변경되도록 하는 작업

 

여기서 ValueAnimator는 후자의 작업을 하지 않는다. 즉 값만 계산해 준다는 것.

만약 계산된 value값을 실제 오브젝트에 반영하고 싶으면 리스너를 통해 직접 값을 바꿔 주어야 한다

 

  • ObjectAnimator

ValueAnimator를 상속받는 애니메이터로 ValueAnimator와의 차이점은 계산된 value값을 실제 오브젝트에 반영해 준다는 점이다.

 

 

  • AnimationSet

애니메이터를 여러개 정의하고 한꺼번에 실행시키고 싶다면? 바로 애니메이션 셋을 이용하면 된다.

여러가지 애니메이터를 정의하고 애니메이션 셋을 하나 생성하여 여기에 등록시키면 동시에 여러개의 애니메이터를 실행 할 수 있다.

 

 

 

 

Evaluator란

프로퍼티 애니메이션을 이해하는데에 Evaluator라는 개념을 아는게 꼭 필요하다

Evaluator는 Animator에서 애니메이션이 진행된 시간에 대한 값을 전달 해 주면, 시간의 정보를 기반으로 애니메이션이 될 value값을 계산해 준다.

 

 

  • IntEvaluator : int값을 계산해주는 evaluator이다
  • FloatrEvalutator : float값을 계산해주는 evaluator이다
  • ArgbEvaluator : hexadecimal로 표현되는 컬러값을 계산해주는 Evaluator이다
  • TypeEvaluator : 유저가 커스텀 제작하여 사용할 수 있는 인터페이스이다

 

 

Interplatators

interpolator는 애니메이션의 보간법에 대해 정의한다. 애니메이션을 빠르게 재생하거나, 처음에는 천천히 나중에는 빠르게 하는 식으로 계산이 가능하다.

 

보간법의 형태 모양은 말로 설명하기 힘드니 아래 사이트에서 그림을 참고하자

http://cogitolearning.co.uk/2013/10/android-animations-tutorial-5-more-on-interpolators/

 

Android Animations Tutorial 5: More on Interpolators | Cogito Learning

Today I will show you how to customise and even create your own interpolators. As discussed previously, the View Animation system provides a number of ready made interpolators. But sometimes you have your own requirements and you just want that interpolato

cogitolearning.co.uk

반응형

 

 

 

 

ValueAnimator를 이용한 Animate 예제

 

ofFloat, ofInt, ofObject같은 메소드를 이용하여 value를 set 해준뒤 start()를 호출하면 된다.

아래 예제에서는 0에서 100까지 1000ms동안 진행되는 애니메이션을 나타낸다.

 

 

아래코드에서 addUpdateListener는 생략되어 있음!

 

kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    ValueAnimator.ofObject(...).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});
animation.start();

 

 

 

만약 float이나 int같은 값이 아닌 나만의 커스텀한 값을 이용해 애니메이션을 만들고 싶다면?

앞서 배운 TypeEvaluator를 재정의 하여 만들면 된다

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
//리스너 생략
animation.setDuration(1000);
animation.start();

 

TypeEvaluatoer는 아래와 같이 정의되어 있으니 참고하면 된다.

public interface TypeEvaluator<T> {
    T evaluate(float var1, T var2, T var3);
}

아래는 대표적인 예제이다

valueAnimator.setEvaluator(new TypeEvaluator<Integer>() {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        return Math.round(startValue + (endValue - startValue) * fraction);
    }
});

 

 

 

ObjectAnimator 사용하기

ObjectAnimator는 ValueAnimator를 상속받는 SubClass임을 기억하자

 

오브젝트 애니메이터는 세가지만 기억하면 된다

 

  • 애니메이션이 될 오브젝트
  • 오브젝트의 프로퍼티 이름, String 형태로
  • end value

 

  • 오브젝트 애니메이션은 ValueAnimator와 다르게 값을 알아서 변환시켜주기 때문에 AnimatorUpdateListener를 굳이 정의 안해주어도 된다.
    하지만 경우에 따라 리스너를 달아줘야 하는 케이스도 있으니 주의
  • 그리고 오브젝트 애니메이션은 getter와 setter를 반드시 정의해 주어야 한다!
    CamelCase 형태로 메소드명을 작성해야 하며, 애니메이션을 진행할 프로퍼티 이름이 foo라고 가정하면
    getter와 setter의 형태는 setFoo(), getFoo() 형태가 되어야 한다.

 

 

다음은 오브젝트 애니메이션의 예제이다

 

textView의 프로퍼티인 translationX 라는 변수를 100f 만큼 변화시키라는 의미이다!

 

kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

 

 

 

 

ObjectAnimator의 리스너 설정

가끔가다 프로퍼티를 변경하고, View를 강제로 다시 그리이 위해 invalidate() 함수를 호출해야 하는 경우가 있다.

View들의 기본 프로퍼티들은 모두 setter에 기본적으로 invalidate()가 포함되어 있다.

 

허나 만약 커스텀뷰를 만들고, 이 커스텀된 프로퍼티에 따라 뷰를 다시그리고 싶다면?

 

onAnimationUpdate() 라는 메소드를 통해 콜백을 정의하고 invalidate를 호출하여야 한다

 

 

 

 

Animation set 사용하여 여러개의 애니메이션 재생

 

앞서 언급된 Animation set을 배워보자. 이 Animation set은 애니메이터를 여러개 정의하면 하나의 묶음으로 구성하여 애니메이션 재생해준다.

또한 애니메이션 세트 안에 애니메이션 세트를 nested 할 수 도 있다.

 

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

 

 

 

 

 

 

Animation Listener

애니메이션 리스느너는 update 리스너만 있는것이 아니다!

 

 

Animator.AnimatorListener

  • onAnimationStart() - 애니메이션이 시작할 떄 불림
  • onAnimationEnd() - 애니메이션이 끝날 떄 불림
  • onAnimationRepeat() - 애니메이션이 반복될 떄 불림
  • onAnimationCancel() - 애니메이션이 취소될 때 불림
  • onAnimationEnd() - 애니메이션이 종료될 때 불림. onAnimationCancel()이 불리면 필연적으로 이것도 불리게 된다.

ValueAnimator.AnimatorUpdateListener

  • onAnimationUpdate() - 애니메이션 매 프레임마다 불린다

 

 

 

Animator.AnimatorListener 를 사용하기 위해선 AnimationListenerAdapter라는 인터페이스를 구현하면 된다.

이 어댑터에는 각각의 리스너들이 텅 비어있는 채로 정되어 있고 원하는 리스너를 정의하여 애니메이션에 등록해주면 된다.

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

 

 

 

 

Animate layout changes to ViewGroup objects

(작성중)

 

Animate view state changes using StateListAnimator

(작성중)

 

 

 

 

커스텀 Interpolator 정의하기

 

나만의 Interpolator를 정의하고 싶다면 TimeInterpolator를 구현하면 된다!

 

public interface TimeInterpolator {
    float getInterpolation(float var1);
}

 

아래는 안드로이드 predefined 되어있는 AccelerateDecelerateInterpolator의 구현 예제이다.

 

 

kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

 

 

 

 

 

View Animation

앞서 프로퍼티 애니메이션을 배웠고 이를 이용하면 거의 모든것에 애니메이션을 줄 수 있다.

하지만 모든것을 할 수 있다는 것은 코드양이 조금 많아진다는 단점이 있다!

 

 

간단한 뷰의 위치나 크기 혹은 alpha값만 바꾸고 싶다면? View Animation을 사용하면 된다.

 

View Animation이란 View안에 내장되어 있는 프로퍼티 애니메이션을 의미한다

 

view.animate()
        .x(10)
        .y(10)
        .setDuration(300)
        .start();

 

코드만 봐도 아주 간단하쥬?

 

 

 

뷰 애니메이션은 다음과 같은 프로퍼티들을 다룰 수 있다

 

 

  • translationX, translationY : 이속성은 현재 뷰 위치에서 얼마나 이동할지를 나타낸다
  • x, y : 화면에서 어느 위치에 있는지 나타낸다
  • scaleX, scaleY : 뷰의 크기를 지정해주는 프로퍼티이다 
  • pivotX, pivotY : 뷰가 회전하거나 크기조정이 발생할 떄 기준이 되는 점을 나타낸다
  • alpha : 뷰의 투명도를 나타낸다

 

 

 

translationX와 x의 차이

간단히 말해 translate는 offset이고 x는 뷰의 절대적인 좌표를 의미한다.

 

가령 예를들어 화면의 크기가 1000x1000 인 화면이 있다고 하자

 

그리고 한 점이 (100,100) 에 위치해 있다.

 

View.translateX(30) => (130 , 100) 으로 이동

View.x(30) => (30, 100) 으로 이동 

 

 

즉 translateX(value)는 value만큼 x축으로 이동하라는 의미이고

x(value)는 x의 좌표를 value로 바꾸라는 의미이다

 

 

 

반응형

댓글