×
Crocus
공부한 내용을 정리하는 블로그로 시작한
Crocus는 2014년 1월 14일 부터 시작하여
현재 월 6만명, 총 1,281,567명의 방문자 수를 기록하고 있습니다.
Donation
이제 많은 사용자들이 이용하는 만큼
더 다양한 서비스 개발/제공을 위해 후원금을 모금하고자 합니다.
후원을 해주시는 분들은 Donators 명단에 성명, 후원금을 기입해드리며
Crocus 블로그가 아닌 다른 곳에 정리해둔 저만의 내용을 공유해 드리고자 합니다.
Account
예금주 : 고관우
신한은행 : 110-334-866541
카카오뱅크 : 3333-01-7888060

👉 후원 페이지 바로가기 Donators
익명 : 5000원(Crocus응원합니다.)
강현대 : 5000원(busyhuman)

안드로이드에서 어떤 물체를 눌렀을 때 물체가 커지게 만들거나 물체를 뗏을 때 물체가 작아지게 만들고 싶은 경우가 있다.

 

이때 에니메이션을 적용해야함은 알겠는데, 이 에니메이션을 어떻게 적용해야할지에 대해 이야기해보고자 한다.

 

ValueAnimator

https://developer.android.com/reference/android/animation/ValueAnimator

 

ValueAnimator  |  Android 개발자  |  Android Developers

ValueAnimator public class ValueAnimator extends Animator Known direct subclasses ObjectAnimator This subclass of ValueAnimator provides support for animating properties on target objects.  TimeAnimator This class provides a simple callback mechanism to li

developer.android.com

 

이 ValueAnimator은 기존 Animation 방식에 비해서 View가 아닌 Object 등 모든 것들에 Animation을 적용 할 수 있다.

 

이 ValueAnimator을 이용하여 특정 duration동안 변화를 줄 수 있다.

 

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View v = new TestView(this);
        setContentView(v);
    }

    private static class TestView extends View {
        Paint CircleFill_dah = new Paint(); // hit of dah duration
        ValueAnimator animator_dah = ValueAnimator.ofInt(100,255);

        public TestView (Context context) {
            super(context);
            setFocusable(true);

            CircleFill_dah.setStyle(Paint.Style.FILL);

            CircleFill_dah.setColor(Color.BLUE);
            CircleFill_dah.setAlpha(50);
            animator_dah.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int alphval = (int) animation.getAnimatedValue();
                    CircleFill_dah.setAlpha(alphval);
                    invalidate();
                }
            });
            
            animator_dah.ofFloat(0f, 1f);
            animator_dah.setDuration(1000);
            animator_dah.start();

        }
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawCircle(50, 50, 50, CircleFill_dah);
        }
    }
}

 

위의 코드에서 아래 코드를 보면 다음과 같다.

0f ~ 1f가 1초동안 나타날 수 있게 분할해주고 이를 start해주면 이때 리스너에서 반응하게 된다.

            animator_dah.ofFloat(0f, 1f);
            animator_dah.setDuration(1000);
            animator_dah.start();

animator에 추가된 리스너에서 onAnimationUpdate가 동작하며 getAnimatedValue를 통해 해당 값을 전달받게된다.

우리는 이 값을 통해 물체의 크기 혹은 다양한 속성들을 조절 할 수 있다. 

           animator_dah.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int alphval = (int) animation.getAnimatedValue();
                    CircleFill_dah.setAlpha(alphval);
                    invalidate();
                }
            });

 

아래에서는 ValueAnimator에 대해 다양한 기능을 알아볼 수 있다.

 

Animating with ValueAnimator

  • TimeInterpolator
  • TypeEvaluator
  • duration
  • startPropertyValue
  • endPropertyValue

 

 // 0f ~ 1f까지 1초동안 변한다.

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start()

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

ValueAnimator가 Object에 직접적인 실제 변화를 주지는 않는다. 이를 위해서는 AnimationListener를 달아서 getAnimatedValue를 통해 계산 된 값을 얻어 변화를 주어야 한다.

 

Animating with ObjectAnimator extends ValueAnimator

timing engine과 ValueAnimator의 값 계산, 타겟 오브젝트의 속성명으로 animate.

 

ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

ObjectAnimator를 사용하기 위해서는 아래 사항을 준수.

  • property Name에 대해서 setter method가 camel 표기 법을 따라서 존재해야 함. (foo 가 setter라면 setFoo() )

    • option 1 : setter 추가
    • option 2 : Wrapper class를 만들어서 setter 추가.
    • option 3 : 대신에 ValueAnimator를 사용.
  • 만약 ObjectAnimator factory method에서 값을 1개만 주면 이는 end value로 간주 된다. 그러므로 ObjectAnimator가 start value를 얻기 위한 getter method가 필요하다. getFoo()
  • property의 type에 따라서 getter, setter는 같은 타입을 갖도록 해야 함.
  • animating하는 property나 object에 따라서 해당 값을 적용 할 View invalidate 할 필요가 있음.

    • 이것은 onAnimationUpdate() callback을 이용하여 처리.
    • 만약 View의 RGB값 변경 같은 경우는 onAnimaionUpdate에서 invalidation을 따로 해줄 필요가 없어짐. 왜냐하면 이미 그런 Drawable에는 setAlpha, getAlpha method가 이미 준비되어 있고, property는 alpha와 같이 이미 해당 이름으로 명시했을 것이기 때문이다.

 

 

Multiple Animations with AnimatorSet

AnimatorSet을 통해 Animation은 여러가지를 동시, 순차적 혹은 지연 시간을 주고 진행 시킬 수 있다.

또한 AnimatorSet은 중복 될 수 있다.

 

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 Listeners

Animator.AnimatorListener

  • onAnimationStart()

    • 애니메이션 시작 될 때
    •  
    • onAnimationEnd()

      • 애니메이션 끝 날 때
  • onAnimationRepeat()

    • 애니메이션이 반복 될 때
  • onAnimationCancel()

    • 애니메이션이 취소 될 때. onAnimationEnd() 도 불림.

ValueAnimator.AnimatorUpdateListener

  • onAnimationUpdate()

    • 애니메이션의 매 프레임마다 불림. 애니메이션 동안에 ValueAnimator가 계산한 값을 이 callback에서 사용해야 함.
    • 값을 사용하기 위해서는 callback에 전달 된 ValueAnimator object에 getAnimatedValue()를 통해 값을 얻음.
    • 위에 설명한 것 처럼 object, property에 따라서 invalidation을 위한 method call이 필요할 수 있음

만약 Animator.AnimatorListener interface를 구현하여 모든 callback을 구현하길 원치 않는다면, AnimatorListenerAdapter 를 상속할 수 있다. (개발자가 override 해서 사용할 수 있도록 모든 callback에 empty method를 제공)

 

ex>

ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
  public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
  }
}

Animating Layout Changes to ViewGroups

LayoutTransition class를 이용하여 ViewGroup 내의 layout changes 에 대해서 animation 할 수 있다.

ViewGroup 내의 View들에 대해서 VIew가 삽입, 삭제, 보이도록 혹은 보이지 않도록 설정함에 따라서 animation 할 수 있다.

LayoutTransition object에는 setAnimator()를 통해 Animator object와 아래 LayoutTransition 상수를 파라미터로 전달하여 애니메이션 할 수 있다.

  • APPEARING - Container에서 보이게 될 때
  • CHANGE_APPEARING - Container에 새 item이 추가 됨으로써 변경 될 때
  • DISAPPEARING - Container에서 안보이게 될 때
  • CHANGE_DISAPPEARING - Containenr에서 다른 item이 삭제 됨으로써 변결 될 때

 

Layout Animation을 위해 위 4가지 Animation을 만들어 설정하거나 기본 Animation을 사용할 수 있다.

default 적용 은 xml에서 단지 Layout에 android:animateLayoutChanges="true" 추가 만으로 가능하다.

 

TypeEvaluator 의 사용

Android system이 알지 못하는 타입을 animate하길 원한다면 TypeEvaluator interface를 구현함으로써 가능하다.

Android known type은 IntEvaluator, FloatEvaluator, ArgbEvaluator이다.

TypeEvaluator interface를 구현할 때는 한가지 메소드만 구현하면 됨.

이 때, Interpolator가 setting되면 계산 되어 fraction으로 들어오기 때문에 fraction만 이용하면 됨.

 

public class FloatEvaluator implements TypeEvaluator {

  public Object evaluate(float fraction, Object startValue, Object endValue) {
    float startFloat = ((Number) startValue).floatValue();
    return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
  }
}

 

Interpolator의 사용

Interpolator는 시간을 계산하여 fraction이라는 현재까지 흐른 시간을 전달.

만약 Android에서 제공하는 Interpolator가 구미에 맞지 않으면 TimeInterpolator interface를 구현하면 됨.

 

AccelerateDecelerateInterpolator

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

LinearInterpolator

publicfloat getInterpolation(float input){ return input; }

 

 

https://darksilber.tistory.com/108