Android 动画系列之2 -- 多种方式实现帧动画

目录

1:使用 AnimationDrawable, 使用xml配置每一帧图片

1:定义frame_list.xml

2:frame_list 设置为 imageView 背景

3:获取ImageView背景并将其转化为 AnimationDrawable

4:调用 animationDrawable.start(); 测试效果如下图:

2:使用线程池、while循环、图片资源列表集合自定义帧动画

TIP:我们会用多种方式实现帧动画效果,其他方式请看下一篇

前言:这里我们先复习一下线程池的用法:

1:创建 BaseFrameAnim 实现公共方法

2:线程方式实现帧动画类 FrameAnimFromThreadInfoGroup 继承 base类

3:FrameAnimFromThreadInfoGroup 中配置 帧图片列表及对应动画工具类参数进行播放测试

Demo源码详见gitlab:

Demo 下载链接:BAnimation


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

其他方式实现帧动画效果,请看下一篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值