自定义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而言,不用另开线程,实现更加方便了!!!
版权声明:本文为博主原创文章,未经博主允许不得转载。

浙公网安备 33010602011771号