허접한 감이 없잖아 있지만 생각보다 다수의 이미지를 순차적으로 화면에 보여주는 애니메이션을 안드로이드에서 구현하기 위해서는 생각할 점이 많습니다. 제가 해보려는것의 위의 단순한 3개의 이미지를 반복해서 순차적으로 보여줄려는 것인데요 생각보다 복잡합니다.
/** * @author Eye */ public class AnimatedImageViewActivity extends Activity { private ImageView mIvAnimation; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 에니메이션을 구동하기 위한 이미지뷰를 가져와 애니메이션을 세팅합니다. mIvAnimation = (ImageView) findViewById(R.id.animation); mIvAnimation.setBackgroundResource(R.anim.anim); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); // 배경이미지로 등록된 Drawable을 가져와 애니메이션을 시작합니다. AnimationDrawable adAnimatedDrawable = (AnimationDrawable) mIvAnimation.getBackground(); adAnimatedDrawable.start(); } }
이 글은 애니메이션 자체에 대해 쓴 글이 아니기 때문에 처음부터 끝까지의 내용을 적지는 않겠습니다. 다만 예제 소스를 그대로 올릴테니 궁금하시면 열어보세요.
자 위의 코드를 한번 봐보겠습니다. 이미지뷰를 findViewById를 이용하여 가져온 뒤에 setBackgroundImage를 이용하여 마치 평소의 이미지를 세팅하는것처럼 이미지를 설정합니다.
곧바로 애니메이션을 실행하고 싶지만 onCreate에서는 에니메이션을 플레이 할 수 없습니다. 그래서 위의 예제에서는 onWindowFocusChanged라는 메소드를 구현하여 그안에 애니메이션을 시작하는 코드를 넣었는데요. getBackground를 통해 얻은 Drawable객체를 AnimationDrawable객체로 캐스팅한 후에 start를 하고 있는것을 알 수 있습니다.
[예제 다운로드]
위의 예제를 실행해 보면 일단 애니메이션이 매우 잘 실행이 됩니다. 하지만 매우 많은 애니메이션을 처리해야 한다거나 적절한 시점에 애니메이션이 플레이되고 정지되어야 하고 적절하게 메모리에서 제거가 되어야 한다면 어떻게 해야 할까요?
아마도 그 모든것을 관리하는 로직을 생각하여 프로그램을 짜야 할 것입니다. 하지만 이 모든것을 자동으로 처리해 주는 방법을 구현해 보겠습니다.
AnimatedImageView.java
/** * 화면에 보여질때 자동으로 시작하고 보이지 않을때 중단되는 * 에니메이션이미지뷰입니다. * * @author Eye */ @RemoteView public class AnimatedImageView extends ImageView { private AnimationDrawable mAnim; private boolean mAttached; /** * 기본 생성자 * * @param context 컨텍스트 */ public AnimatedImageView(Context context) { super(context); } /** * 기본 생성자 * * @param context 생성자 * @param attrs 속성들 */ public AnimatedImageView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 애니메이션을 변경하고 시작합니다. */ private void updateAnim() { Drawable drawable = getDrawable(); if(mAttached && mAnim != null) { mAnim.stop(); } if(drawable instanceof AnimationDrawable) { mAnim = (AnimationDrawable)drawable; if (mAttached) { mAnim.start(); } } else { mAnim = null; } } @Override public void setImageDrawable(Drawable drawable) { super.setImageDrawable(drawable); updateAnim(); } @Override public void setImageResource(int resid) { super.setImageDrawable(null); super.setImageResource(resid); updateAnim(); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); if (mAnim != null) { mAnim.start(); } mAttached = true; } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAnim != null) { mAnim.stop(); } mAttached = false; } @Override protected void finalize() throws Throwable { clearAnimation(); super.finalize(); } }
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <kr.pe.theeye.animatedimageview.AnimatedImageView android:id="@+id/animation" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
위와 같은 변경으로 인해 이제 우리의 코드는 아래와 같이 단순해졌습니다. 아래가 전부입니다.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 에니메이션을 구동하기 위한 이미지뷰를 가져와 애니메이션을 세팅합니다. mIvAnimation = (AnimatedImageView) findViewById(R.id.animation); mIvAnimation.setImageResource(R.anim.anim); }
이제부터는 저 이미지뷰가 화면에 보이게 되면 자동으로 애니메이션이 시작되며 화면에 보이지 않게 될 경우 자동으로 애니메이션이 정지됩니다. 또한 많은 애니메이션을 로드해도 적절한 시기에 메모리 반환을 최대한 할수 있도록 노력하였습니다. (하지만 생각만큼 완벽하진 않습니다. 능력 미달…) 아무튼 잘 되는 것을 보실 수 있습니다. 완성된 예제를 올려두겠습니다.
[예제다운로드]