반응형

 

Animation in Android

 

안드로이드 프로그래밍을 하다 보면 초라한 UI를 제공하지 않기 위해 애니메이션을 추가하여 좀 더 고급스러운 App을 만들어 내고자 한다.

 

이때 Animation을 쓰다보면 여러가지 많은 방법들이 존재하고 

ValueAnimator, AnimatorSet, ViewPropertyAnimator ... 등등의 다양한 방법 중 하나를 선택하여 쓰게 된다.

 

이렇게 안드로이드는 애니메이션 기능 위해 강력한 Animator라는 클래스를 제공해준다.

 

하지만 애니메이션을 만들어 낼 수 있는 방법들이 다양함에도 불구하고 대부분 비슷하게 동작하기 때문에 적재적소로 선택하기가 힘들다.

 

따라서 아래 내용부터 언제 어떤 Animator을 사용해야하는지에 대해 가이드를 하고자 한다.  

 

이번 포스트를 통해 각각의 방법에 대해 목적을 제대로 익혀보자.

 

https://youtu.be/N_x7SV3I3P0?list=PLmEM3-F7iVMlm936VEVxlITwdn60XJQX0&t=355

 

 

 

 

When and how to use

 

 

 


1. 간단한 애니메이션에서는 ViewPropertyAnimator을 사용하자

 

오직 하나의 뷰에서만 애니메이션이 동작하길 원하고, repeat, reverse, play together 등등 복합적으로 애니메이션이 동작하지 않아도 되는 경우에는 오직 ViewPropertyAnimator만을 사용해도 충분하다.


View.animate()
    .alpha(0.5f)
    .scaleX(0.5f)
    .scaleY(0.5f)
    .setDuration(3000)
    .withStartAction(() -> { Write something to do when the animation starts })
    .withEndAction(() -> { Write something to do when the animation starts })

위와 같은 방식으로 사용하면 해당 뷰는 현재 상태로부터 3초동안 alpha가 0.5로, scale이 0.5로 진행되게 되며

애니메이션 시작, 종료 시 필요한 동작들을 Runnable로 실행 시킬 수 있다.

 

이 방법의 장점객체를 직접 Animator obj로 인스턴스화 할 필요 없으므로, 간결한 애니메이션을 작성하고자 한다면 ViewPropertyAnimator을 선택하는 것이 바람직하다.

 

하지만 ViewPropertyAnimator에는 단점이 존재한다.

 

- 반복적인 Animation 만들 수 없다.

- 오직 end value만을 설정 할 수 있고 start value를 설정 할 수 없다. (즉, 뷰의 현재 상태에서부터 end로만 갈 수 있다.)

- ViewPropertyAnimator에서는 오직 간단한 애니메이션만 수행 할 수 있다.

- 순차적인 애니메이션(A애니메이션 다음 B애니메이션 ...) 혹은 복합적인 애니메이션(A, B를 동시에 실행하는 애니메이션)이 불가능하다.

 

 

 

 


2. 반복적인 애니메이션이 필요하다면 ObjectAnimator를 사용하자

 

하나의 뷰에서 간단한 애니메이션을 이용하고자 하지만 반복적으로 동작기를 바란다면, ObjectAnimator를 사용하면 된다.


ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationY", 300f);
                    anim.setDuration(5000);
                    anim.setRepeatCount(ValueAnimator.INFINITE);
                    anim.setRepeatMode(ValueAnimator.REVERSE);
                    anim.start();

 

ViewPropertyAnimator와 다르게 이것은 Repeat이라는 것을 가질 수 있기 때문에 애니메이션을 반복적으로 사용할 수 있는 장점이 있다.

 

ObjectAnimator의 특별한 기능이라고 한다면 XML을 이용하여 애니메이션을 만들 수 있는 장점이 있다.

 

< res/animator/sample.xml >

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_decelerate"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:duration="5000"
    android:propertyName="textColor"
    android:valueFrom="#FFFF0000"
    android:valueTo="#FF0000FF"
    android:valueType="colorType"/>
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(getActivity(), R.animator.sample);
set.setTarget(fab); // set the view you want to animate
set.start();

 

하지만 해당 ObjectAnimator도 결국 기본적인 애니메이션 속성만 가지고 있을 뿐,

순차적인 애니메이션(A애니메이션 다음 B애니메이션 ...) 혹은 복합적인 애니메이션(A, B를 동시에 실행하는 애니메이션)이 불가능하기에 간단한 애니메이션에서만 사용 할 수 있다.

 

 

 

 


3. 복합적인 애니메이션 사용을 위해서는 PropertyValueHolders를 사용하자

 

하나의 뷰에서 하나 이상의 애니메이션을 동시에 실행시키고자 한다면 PropertyValueHolder을 사용하면 된다.

이 PropertyValuesHolder는 설정 후 ObjectAnimator에 아래와 같이 사용할 수 있다.


 

PropertyValuesHolder rotationX = PropertyValuesHolder.ofFloat(
    View.ROTATION_X, 0f, 3600f)
PropertyValuesHolder textColor = PropertyValuesHolder.ofInt(
    "textColor",
    Color.parseColor("#FFFF0000"),
    Color.parseColor("#FF0000FF")
)
textColor.setEvaluator(ArgbEvaluator())

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(View, rotationX, textColor);
animator.setDuration(5000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setRepeatCount(INFINITE);
animator.setRepeatMode(REVERSE);
animator.start();

PropertyValuesHolder 기본적인 애니메이션 속성들뿐만 아니라 리플렉션 (textColor, backgroundColor 등등)을 통해 모든 뷰 객체 속성을 사용 할 수 있다.

 

PropertyValuesHolder도 마찬가지로 XML을 통해 애니메이션 생성이 가능하다는 장점이 있다.

 

 

< res/animator/custom_animator.xml >

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_decelerate"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:duration="5000" >
    <propertyValuesHolder
        android:propertyName="rotationX"
        android:valueFrom="0"
        android:valueTo="3600"
        android:valueType="floatType" />
    <propertyValuesHolder
        android:propertyName="textColor"
        android:valueFrom="#FFFF0000"
        android:valueTo="#FF0000FF"
        android:valueType="colorType" />
</objectAnimator>
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(getActivity(), R.animator.custom_animator);
set.setTarget(fab); // set the view you want to animate
set.start();

 

PropertyValuesHolder의 단점 복합 애니메이션 처리가 되지만, 하나의 뷰에 대해서만 여러 애니메이션을 만들어 낼 수 있기에 여러 뷰에 대해 동시에 진행하지는 못하는 단점이 있다.

 

 

 

 


4. 복합 애니메이션 및 순차 애니메이션을 위해서는 AnimatorSet을 사용하자

 

하나의 뷰가 아닌 여러개의 뷰가 존재할 때, 모든 뷰가 동시에 애니메이션이 동작해야할 때

(뷰 A는 오른쪽으로, 뷰 B는 왼쪽으로)

 

혹은 하나의 뷰에서 순차적으로 여러개의 애니메이션이 동작해야할 때

(뷰 A가 오른쪽으로 3초 갔다가 왼쪽으로 2초 갔다가 아래로 5초)

 

이러한 복합적인 요소들이 상호작용할 때 AnimatorSet을 사용한다.


 

PropertyValuesHolder rotationX = PropertyValuesHolder.ofFloat(
    View.ROTATION_X, 0f, 3600f)
PropertyValuesHolder textColorX = PropertyValuesHolder.ofInt(
    "textColor",
    Color.parseColor("#FFFF0000"),
    Color.parseColor("#FF0000FF")
)
textColorX.setEvaluator(ArgbEvaluator())

// PropertyValuesHolder을 통해 X에 관한 애니메이션을 설정
ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(View, rotationX, textColor);
animator.setDuration(5000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());

PropertyValuesHolder rotationY = PropertyValuesHolder.ofFloat(
    View.ROTATION_X, 0f, 3600f)
PropertyValuesHolder textColorY = PropertyValuesHolder.ofInt(
    "textColor",
    Color.parseColor("#FF0000FF"),
    Color.parseColor("#FFFF0000")
)
textColorY.setEvaluator(ArgbEvaluator())

// PropertyValuesHolder을 통해 Y에 관한 애니메이션을 설정
ObjectAnimator animator2 = ObjectAnimator.ofPropertyValuesHolder(View, rotationX, textColor);
animator.setDuration(5000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();


// X에 관한 애니메이션 이후 Y에 관한 애니메이션이 동작하도록 animatorSet 생성
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(animator2).after(animator1);
animatorSet.start();

 

ObjectAnimator, PropertyValuesHolder 및 AnimatorSet 세가지 객체의 조합으로 다양하고 복합적인 애니메이션을 구현할 수 있다.

 

하지만 AnimatorSet의 한 가지 단점반복적인 애니메이션이 불가능하는 단점이 있다.

 

** 마찬가지로 animatorSet도 XML 구현이 가능하다. **

 

 

 

 


5. 애니메이션의 커스터마이징을 극대화 시키기 위해서는 ValueAnimator을 사용한다.

 

뷰 또는 객체의 속성이 아닌것애니메이션을 적용하려는 경우

가장 기본적인 애니메이터 클래스인 ValueAnimator를 사용해야한다.


 

아래에는 ValueAnimator을 커스텀을 잘 나타낸 코드를 보여주고있다.

 

ValueAnimatorAnimatorSet를 혼합하여 사용하면 가장 화려한 애니메이션을 만들 수 있다.

하지만 그만큼 cost가 많이 드는 것은 감안해야 한다.

 

public static void startAnimation(final int view, final Activity activity) {
    final int start = Color.parseColor("#FDB72B");
    final int mid = Color.parseColor("#88FDB72B");
    final int end = Color.TRANSPARENT;


    final ArgbEvaluator evaluator = new ArgbEvaluator();
    View preloader = activity.findViewById(R.id.gradientPreloaderView);
    preloader.setVisibility(View.VISIBLE);
    final GradientDrawable gradient = (GradientDrawable) preloader.getBackground();

    ValueAnimator animator = TimeAnimator.ofFloat(0.0f, 1.0f);
    animator.setDuration(500);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setRepeatMode(ValueAnimator.REVERSE);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Float fraction = valueAnimator.getAnimatedFraction();
                int newStrat = (int) evaluator.evaluate(fraction, start, end);
                int newMid = (int) evaluator.evaluate(fraction, mid, start);
                int newEnd = (int) evaluator.evaluate(fraction, end, mid);
                int[] newArray = {newStrat, newMid, newEnd};
                gradient.setColors(newArray);
        }
    });

    animator.start();
}

public static void stopAnimation(final int view, final Activity activity){
    ObjectAnimator.ofFloat(activity.findViewById(view), "alpha", 0f).setDuration(125).start();
}
//gradient_preloader
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:startColor="#FDB72B"
        android:endColor="#00000000"
        android:angle="0"/>
</shape>
<View
    android:id="@+id/gradientPreloaderView"
    android:layout_width="match_parent"
    android:visibility="gone"
    android:layout_height="@dimen/basic_8_dp"
    android:background="@drawable/gradient_preloader" />

 

 

 

기본적인 ValueAnimator 기능에 대해서는 이전 포스트인 곳에서 자세히 기록해두었으니 해당 포스트를 따라 가보도록 한다.

 

https://www.crocus.co.kr/1671

 

ValueAnimator을 이용한 애니메이션 만들기

안드로이드에서 어떤 물체를 눌렀을 때 물체가 커지게 만들거나 물체를 뗏을 때 물체가 작아지게 만들고 싶은 경우가 있다. 이때 에니메이션을 적용해야함은 알겠는데, 이 에니메이션을 어떻게

www.crocus.co.kr

 

 

 

https://medium.com/better-programming/which-android-animator-to-use-ced54e21d317

반응형