目录
1:使用 AnimationDrawable, 使用xml配置每一帧图片
3:获取ImageView背景并将其转化为 AnimationDrawable
4:调用 animationDrawable.start(); 测试效果如下图:
2:使用线程池、while循环、图片资源列表集合自定义帧动画
2:线程方式实现帧动画类 FrameAnimFromThreadInfoGroup 继承 base类
3:FrameAnimFromThreadInfoGroup 中配置 帧图片列表及对应动画工具类参数进行播放测试
1:使用 AnimationDrawable, 使用xml配置每一帧图片
1:准备好的图片放在 res/drawable 下
2:drawable 文件夹下定义动画XML,或者java编程(AnimationDrawable)配置帧图片
3:view 设置图片资源,调用 AnimationDrawable.start() 方法
1:定义frame_list.xml
XML含义说明:
duration:每一帧图片持续市场
onshot: fase 表示动画循环播放;true 直播放一次,并停留在最后一帧
2:frame_list 设置为 imageView 背景
runImg.setBackgroundResource(R.drawable.frame_list);
3:获取ImageView背景并将其转化为 AnimationDrawable
animationDrawable = (AnimationDrawable) runImg.getBackground();
4:调用 animationDrawable.start(); 测试效果如下图:
2:使用线程池、while循环、图片资源列表集合自定义帧动画
TIP:我们会用多种方式实现帧动画效果,其他方式请看下一篇
1:创建 BaseFrameAnim 实现公共方法
2:线程方式实现帧动画类 FrameAnimFromThreadInfoGroup 继承 base类
3:配置其他方法
前言:这里我们先复习一下线程池的用法:
线程池的核心方法为 ThreadPoolExecutor 其构造方法传参说明
return new ThreadPoolExecutor(
10,//核心线程数
10,//最大线程数
0,//线程数大于核心,多余空闲线程存活时间
TimeUnit.SECONDS,//时间单位
new LinkedBlockingDeque<>(10),//线程队列
/* 需将 runnable new Thread的构造方法中 */
runnable -> new Thread(runnable, taskName),//自定义名称线程池
new RejectHandler(taskName)//被拒策略
);
1:方法中线程工厂中 runnable 需要传入 new Thread中;
2:最后一个为被拒策略,当线程池满我们来自行处理新提交的任务
private static class RejectHandler implements RejectedExecutionHandler {
private String threadName;
public RejectHandler(String threadName) {
this.threadName = threadName;
}
/* 当线程池满,新提交的任务 runnable,会在这里返回;executor 为执行此任务的线程池 */
@Override
public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
Log.e("ThreadPoolCustomAnim", "rejectedExecution");
if (map.containsKey(threadName)) {
map.get(threadName).shutdown();
map.remove(threadName);
}
executor.shutdown();
submit(threadName, runnable);
}
}
3:其余代码
private static Map<String, ThreadPoolExecutor> map = new HashMap<>();
public static Future submit(String taskName, Runnable runnable) {
if (!map.containsKey(taskName)) {
map.put(taskName, getPoolExecutor(taskName));
}
return map.get(taskName).submit(runnable);
}
1:创建 BaseFrameAnim 实现公共方法
先配置公共方法及公共变量,动画涉及到的有:
duration、是否重复、播放动画的view、资源列表、播放帧下标、开始、停止、释放
public abstract class BaseFrameAnim {
private static final String TAG = "BaseFrameAnim";
private Handler handler = new Handler(Looper.getMainLooper());
/* 每一帧显示时间间隔 ms */
public long duration = 200l;
/* 是否重复 */
public boolean isRepeat = false;
/* 执行动画的image */
public ImageView animImgView;
/* 动画资源列表 */
public List<Integer> imgResList = new ArrayList<>();
/* 当前播放帧 下标 */
public int index = 0;
/* 运行在主线程 */
public void runOnUIThread(Runnable runnable) {
handler.post(runnable);
}
/* 设置动画背景资源 */
public BaseFrameAnim setAnimBitmapRes(List<Integer> imgListRes) {
this.imgResList = imgListRes;
return this;
}
/* 绑定ImageView */
public BaseFrameAnim bindImageView(ImageView imageView) {
this.animImgView = imageView;
return this;
}
/* 是否重复,默认否 */
public BaseFrameAnim setRepeat(boolean repeat) {
isRepeat = repeat;
return this;
}
/* 设置每一帧的时间间隔 */
public BaseFrameAnim setDuration(long duration) {
this.duration = duration;
return this;
}
/* 动画开始,开始伴随着重置 */
protected void startVerify() {
Log.e(TAG, "start");
/* 设置view */
if (animImgView == null) {
Log.e(TAG, "animImg null");
return;
}
if (imgResList == null || imgResList.size() == 0) {
Log.e(TAG, "imgResList null ");
return;
}
}
protected void addIndex() {
index++;
if (index < imgResList.size()) {
return;
}
if (isRepeat) {
index = 0;
return;
}
index = 0;
release();
}
protected abstract void release();
}
2:线程方式实现帧动画类 FrameAnimFromThreadInfoGroup 继承 base类
/**
* 使用线程池,和集合逐帧显示
*/
public class FrameAnimFromThread extends BaseFrameAnim {
private static final String TAG = "ThreadPoolCustomAnim";
private Future future;
private boolean isFutureCancle = true;
public boolean isAnimStart = false;
/* 动画开始,开始伴随着重置 */
public void start() {
startVerify();
release();
isAnimStart = true;
future = ThreadPool.submit("frameAnim", () -> {
while (isAnimStart) {
/* 设置图片 */
runOnUIThread(() -> {
animImgView.setImageResource(imgResList.get(index));
/* 配置下一帧 */
addIndex();
});
/* 暂停duration */
if (isFutureCancle) {
return;
}
try {
Thread.sleep(duration);
} catch (InterruptedException err) {
Log.e(TAG, err.getMessage());
}
}
});
}
/* 动画结束 */
public void stop() {
isAnimStart = false;
release();
}
protected void release() {
isAnimStart = false;
isFutureCancle = true;
if (future != null) {
future.cancel(true);
future = null;
}
isFutureCancle = false;
}
}
3:FrameAnimFromThreadInfoGroup 中配置 帧图片列表及对应动画工具类参数进行播放测试
//初始化数据
List<Integer> resList = new ArrayList<>();
resList.add(R.drawable.frame_1);
resList.add(R.drawable.frame_2);
resList.add(R.drawable.frame_3);
resList.add(R.drawable.frame_4);
resList.add(R.drawable.frame_5);
resList.add(R.drawable.frame_6);
resList.add(R.drawable.frame_7);
resList.add(R.drawable.frame_8);
//创建动画实例
FrameAnimFromThread anim = new FrameAnimFromThread();
//配置动画参数
anim
.setAnimBitmapRes(resList)
.bindImageView(imageView)
.setRepeat(true)
.setDuration(200l);
//onDetachedFromWindow 方法中调用 动画stop(stop中会调用动画的释放)
anim.stop();
测试播放效果如下:
Demo源码详见gitlab:GitHub - BianJianZhou/BAnimation: 动画demo:所有动画实现方式动画demo:所有动画实现方式. Contribute to BianJianZhou/BAnimation development by creating an account on GitHub.
https://github.com/BianJianZhou/BAnimation
Demo 下载链接:BAnimation
其他方式实现帧动画效果,请看下一篇