Tag Archives: 애니메이션

[Android] 애니메이션의 시작과 끝을 고민할 필요없는 AnimatedImageView 만들기

anim_1.pnganim_2.png anim_3.png
허접한 감이 없잖아 있지만 생각보다 다수의 이미지를 순차적으로 화면에 보여주는 애니메이션을 안드로이드에서 구현하기 위해서는 생각할 점이 많습니다. 제가 해보려는것의 위의 단순한 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);
}

이제부터는 저 이미지뷰가 화면에 보이게 되면 자동으로 애니메이션이 시작되며 화면에 보이지 않게 될 경우 자동으로 애니메이션이 정지됩니다. 또한 많은 애니메이션을 로드해도 적절한 시기에 메모리 반환을 최대한 할수 있도록 노력하였습니다. (하지만 생각만큼 완벽하진 않습니다. 능력 미달…) 아무튼 잘 되는 것을 보실 수 있습니다. 완성된 예제를 올려두겠습니다.

[예제다운로드]

톱을 노려라 1 건버스터 & 톱을 노려라 2 다이버스터

사용자 삽입 이미지4화에서 각성하는 노노!

사용자 삽입 이미지우주괴물이라고만 생각했던 버스터 군단

사용자 삽입 이미지행성을 두조각 내어버린다; 여러 메카 시리즈중에 지존 메카가 아닐까;

이것이 정말로 제대로 된 메카닉 물일까? 우주와 관련된 애니메이션을 찾다가 가이낙스가 만들었다길래 본 애니메이션이다.

애니메이션은 정확히 우주/시간/빛이 주제인것 같다. 이런식의 전개는 지금까지 본적이 없었다.

1편의 경우 주인공 노리코의 지구를 구하기 위한 힘겨운 싸움이 주제이고 2편의 경우는 노노와 라르크의 이야기가 되겠다.

노노 그 자체가 말도 안되는 버스터머신7호였다니!!!

1편을 보고 기억에 남는 대사가 있다면… “우주는 추억마저도 빨아들여 버리나 보다…”였다.

고등학교 생활 4개월만에 우주로 나가 건버스터로 한번 휘젓고 오니 지구는 이미 몇년이 지나버린 상태였다.

지구로 돌아오자마자 노리코의 졸업식이 진행되고, 그때 노리코의 독백으로 저 대사가 나온다.

몇시간의 미션 수행후에 돌아오면 6개월이 지나있고, 뉴턴의 상대성 이론이 완벽하게 적용되는 다차원적인 시간개념?이 왜이렇게 가슴아프게 다가오는 것일까.

2편의 마지막 엔딩을 보다 보니 1편의 엔딩이 오버랩 되면서 진한 감동과 묘한 여운을 남긴다. 꼭 1편을 보고 2편을 봐야 하는 애니중 하나…

PS : 툭하면 가슴팍 찟어대는 오타쿠틱한 부분만 없었더라면 참 좋았을텐데;

사용자 삽입 이미지
만약 신에게도 소원이 있다면, 그것은 누구에게 부탁해야 할까?

사용자 삽입 이미지어떻게 해서든 그녀를 만나 이야기 하고 싶어.

사용자 삽입 이미지‘반파당한 버스터머신 1&2호’

사용자 삽입 이미지1만 2천년 후의 지구인가…

사용자 삽입 이미지인간은? 불빛이 보이질 않아요.

사용자 삽입 이미지역시, 인류는 멸망해 버린걸까?

사용자 삽입 이미지네가 계속 동경해오던 전설의 여자 아이…

사용자 삽입 이미지노노리리가 오늘밤 돌아오니까!

사용자 삽입 이미지어서오세요.

사용자 삽입 이미지사용자 삽입 이미지사용자 삽입 이미지고마워, 건버스터!

사용자 삽입 이미지그날 밤, 버스터 머신 1호2호 및 탑승자가 귀환했다.