自定义ImageView实现播放帧动画

对于帧动画的显示有多种不同的实现方式,帧动画的图片有两种不同的情形,一种是多个单张图片,放在animation-list对应的xml里面,采用轮播的方式进行;另一种是一张大图片排列不同的小图片,之前实现的方式是采用继承SurfaceView,另开线程,逐步分割图片显示,同样也是轮播的方式实现动画,现在我们综合以上两种实现方式,自定义自己实现一张大图的帧动画播放(ps:有时候为了便于维护,需要一张大图实现的帧动画,而不是多张小图片)
图片资源如下:

资源图片

播放简单可爱的图片来展示效果;
关键代码,自定义的ImageView:

package com.example.animationtest;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
/**
 * 自定义ImageView
 * @author xutao
 *
 */
public class AnimationControl extends ImageView{

    private Bitmap resourceBip; //播放的图片资源
    private int duration; //时间间隔
    private boolean positive; //正向还是反向播放
    private int repeatCount; //重复播放的次数;0、循环
    private int playAfter; //播放之后的动作
    private MyAnimationDrawable animationDrawable; //播放的资源集合

    public AnimationControl(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.animationView);
        int resId = array.getResourceId(R.styleable.animationView_img, 0);
        resourceBip = BitmapFactory.decodeResource(context.getResources(), resId);
        duration = array.getInt(R.styleable.animationView_duration, 500);
        positive = array.getBoolean(R.styleable.animationView_positive, true);
        repeatCount = array.getInt(R.styleable.animationView_repeat_count, 0);
        playAfter = array.getInt(R.styleable.animationView_play_after, 0);
        int column = array.getInt(R.styleable.animationView_column_number, 1);
        int row = array.getInt(R.styleable.animationView_row_number, 1);
        array.recycle();

        animationDrawable = new MyAnimationDrawable();
        initAnimation(column, row);
    }

    public void initAnimation(int column, int row) {
        int w = resourceBip.getWidth()/column;
        int h = resourceBip.getHeight()/row;

        if(positive) {
            for (int i = 0; i < row; i++) {
                int y = h*i;
                for (int j = 0; j < column; j++) {
                    int x = w*j;
                    Drawable drawable = new BitmapDrawable(getResources(), Bitmap.createBitmap(resourceBip, x, y, w, h));
                    animationDrawable.addFrame(drawable, duration);
                }
            }
        } else {
            for (int i = row-1; i >= 0; i--) {
                int y = h*i;
                for (int j = column-1; j >= 0; j--) {
                    int x = w*j;
                    Drawable drawable = new BitmapDrawable(getResources(), Bitmap.createBitmap(resourceBip, x, y, w, h));
                    animationDrawable.addFrame(drawable, duration);
                }
            }
        }
        setImageDrawable(animationDrawable);
        animationDrawable.setOneShot(false);
        animationDrawable.setRepeatCount(repeatCount);
        animationDrawable.setAnimationEndListener(new MyAnimationDrawable.AnimationEndListener() {

            @Override
            public void onEnd() {
                // TODO Auto-generated method stub
                switch (playAfter) {
                case 0:

                    break;
                case 1:
                    setVisibility(View.INVISIBLE);
                    break;
                case 2:
                    setVisibility(View.GONE);
                    break;
                default:
                    break;
                }
            }
        });
        animationDrawable.start();
    }

    public Drawable getCurrentDrawable() {
        return animationDrawable.getCurrent();
    }

    public Drawable getIndexDrawable(int index) {
        return animationDrawable.getFrame(index);
    }
}

由于自定义了styleable,所以附上attr.xml代码,该代码放在value文件夹下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="animationView">
        <!-- 要播放的图片资源 -->
        <attr name="img" format="reference" />
        <!-- 播放时间间隔 -->
        <attr name="duration" format="integer" />
        <!-- 图片行数 -->
        <attr name="row_number" format="integer" />
        <!-- 图片列数 -->
        <attr name="column_number" format="integer" />
        <!-- ture为正向播放图片,false为反向播放图片 -->
        <attr name="positive" format="boolean" />
        <!-- 小于等于0为循环播放 -->
        <attr name="repeat_count" format="integer" />
        <!-- 非循环播放之后的响应;无效果 、不可见、隐藏-->
        <attr name="play_after">
            <flag name="visible" value="0" />
            <flag name="invisible" value="1" />
            <flag name="gone" value="2" />
        </attr>
    </declare-styleable>

</resources>

由于系统自带的AnimationDrawable不具有播放次数和播放结束的监听事件的功能,因此需要自定义AnimationDrawable,代码如下:

package com.example.animationtest;
import android.graphics.drawable.AnimationDrawable;
/**
 * 自定义AnimationDrawable
 * 实现播放次数控制和播放结束回调事件
 * 
 * @author xutao
 *
 */
public class MyAnimationDrawable extends AnimationDrawable {

    private int repeatCount = 0;
    private boolean isRepeat = true;
    private AnimationEndListener listener;

    public MyAnimationDrawable() {
        super();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        if(!isRepeat) {
            repeatCount --;
            if(repeatCount == 1) {
                super.unscheduleSelf(this);
                if(listener != null) listener.onEnd();
            }
        }
    }

    public void setRepeatCount(int num) {
        if(num == 0) isRepeat = true;
        else {
            isRepeat = false;
            repeatCount = num*getNumberOfFrames();
        }
    }

    public void setAnimationEndListener(AnimationEndListener ls) {
        listener = ls;
    }

    /**
     * 动画播放结束回调接口
     * @author user
     *
     */
    public interface AnimationEndListener {
        public void onEnd();
    }
}

基本代码就是这些,对了,还有布局文件代码:

    <com.example.animationtest.AnimationControl
        android:id="@+id/main_control"
        android:layout_width="100dp"
        android:layout_height="100dp" 
        animation:column_number="7"
        animation:duration="100"
        animation:img="@drawable/day"
        animation:play_after="invisible"
        animation:positive="true"
        animation:repeat_count="8"
        animation:row_number="1" />

好了,就是这些代码了,封装之后感觉好简单啊,相对于SurfaceView而言,不用另开线程,实现更加方便了!!!

DEMO下载地址 ^-^

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-10-26 17:23  骑着马儿去拉萨  阅读(1304)  评论(0)    收藏  举报