Android -- [SelfView] 多动画效果图片播放器

Android -- [SelfView] 多动画效果图片播放器

效果(录制的有点卡)


1. 引用:
xml 复制代码
    <com.nepalese.virgolib.widget.image.BaseImageView
        android:id="@+id/base_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
2. 接口:
java 复制代码
private BaseImageView baseImageView;
//绑定
baseImageView = findViewById(R.id.base_image);
//设置动画类型
baseImageView.setAnimType(type);
//设置图片资源
baseImageView.setImageResource(path);
3. BaseImageView.java
java 复制代码
package com.nepalese.virgolib.widget.image;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Movie;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by Administrator on 2024/10/10.
 * Usage:自带动画的图片播放器: 两张图之间
 */

public class BaseImageView extends View {
    private static final String TAG = "BaseImageView";

    private static final long COM_INTERVAL = 500L;//通用动画时长
    private static final int ANIM_NUM = 10;//动画效果数(除随机)
    private static final int LENTH = 40;//像素跨值|cube 边长//按最大1920*1080容器,45时,差不多拆分1000个
    private static final int MAX_CACHE = 10;//最大缓存数量
    private static final int MAX_ALPHA = 255;//最大透明度
    private static final int MAX_GRADE = 180;//最大旋转角度

    public static final int ANIM_NONE = 0;//无动画
    public static final int ANIM_FADE = 1;//淡入淡出 默认
    public static final int ANIM_RIGHT = 2;//右进左出
    public static final int ANIM_SCALE = 3;//中心缩放
    public static final int ANIM_SCALE2 = 4;//中心缩放, 上一张不变
    public static final int ANIM_JUMP = 5;//弹跳退出
    public static final int ANIM_UP = 6;//底部上推
    public static final int ANIM_BOTTOM_UP = 7;//底部上浮
    public static final int ANIN_ROTATE = 8;//顺时针旋转
    public static final int ANIM_ROLL = 9;//左下角顺时针旋转 + 右移

    public static final int ANIM_CRASH = 10;//破碎效果
    public static final int ANIM_RANDOM = 99;//随机

    private final Context context;
    private Drawable[] drawables;//操作的两张图
    private ValueAnimator animator;//动画
    private Paint paint;//画笔
    private Movie movie;//用于承载gif文件
    private Rect rectLast, rectCur, rectJump;//上一张、当前图片位置
    private List<CubeBean> pixelList;
    private HashMap<String, Drawable> cacheMap;//图片缓存

    private int width, height;//控件宽高
    private int animType;//动画类型
    private int curIndex;//0|1
    private int CV;//线性变化的基础值
    private int JUMP_THRESHOLD;//跳动偏移阈值 px
    private int rotate, cX, cY;//当前旋转角度
    private int alphaLast, alphaCur;//上一张、当前图片透明值[0-255]
    private int leftLast, leftCur;//上一张、当前图片左上点x[0-width]
    private int topLast, topCur;//上一张、当前图片左上点xy[0-height]
    private float time;//动画运行时间
    private float whRate;//宽高比
    private long INTERVAL_ANIMATION;//动画时长,按动画类型分配
    private long gifPlayTime;//当前gif已播放时长
    private boolean isSecond;//第二部分
    private boolean isOver;//动画结束
    private boolean isRandom;//随机动画效果
    private boolean isGif;//当前为gif 文件?
    private String lastPath;//记录上一张图片路径:相同的文件则不切换

    public BaseImageView(Context context) {
        this(context, null);
    }

    public BaseImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    private void init() {
        time = 0;
        curIndex = -1;
        gifPlayTime = 0;
        isSecond = false;
        isOver = false;
        isRandom = false;
        isGif = false;
        animType = ANIM_NONE;
    }

    /**
     * 设置|更改布局时调用
     *
     * @param width  容器宽
     * @param height 容器高
     */
    public void initLayout(int width, int height) {
        this.width = width;
        this.height = height;
        this.whRate = width * 1f / height;
        initAnimator();
    }

    private void initAnimator() {
        cancelAnim();
        resetAnimator();
    }

    private void resetAnimator() {
        switch (animType) {
            case ANIM_NONE:
                CV = 0;
                break;
            case ANIM_FADE:
                CV = MAX_ALPHA; //透明值
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIN_ROTATE:
                CV = MAX_GRADE;
                cX = width / 2;//旋转中心
                cY = height / 2;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_ROLL:
                CV = MAX_GRADE;
                cX = 0;//旋转中心
                cY = height;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_RIGHT:
                CV = width;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_UP:
                CV = height;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_BOTTOM_UP:
                CV = height;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_SCALE:
                rectLast = new Rect();
                rectCur = new Rect();
                CV = width / 2;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_SCALE2:
                rectCur = new Rect();
                CV = width / 2;
                INTERVAL_ANIMATION = COM_INTERVAL;
                break;
            case ANIM_CRASH:
                if (paint == null) {
                    paint = new Paint();
                    paint.setAntiAlias(true);
                    paint.setStyle(Paint.Style.FILL);
                }
                if (pixelList == null) {
                    pixelList = new ArrayList<>();
                }
                CV = 128;
                INTERVAL_ANIMATION = 1280L;
                break;
            case ANIM_JUMP:
                rectJump = new Rect();
                JUMP_THRESHOLD = Math.max(width / 8, 30);
                CV = width + JUMP_THRESHOLD;
                INTERVAL_ANIMATION = 800L;
                break;
        }

        if (CV > 0) {
            animator = ValueAnimator.ofInt(0, CV);
            animator.setDuration(INTERVAL_ANIMATION);
            animator.setInterpolator(new LinearInterpolator());//插值器设为线性
        } else {
            animator = null;
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (w > 0 && h > 0) {
            initLayout(w, h);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (drawables == null) {
            return;
        }

        if (isGif && this.getVisibility() == VISIBLE) {
            drawGif(canvas);
            return;
        }

        switch (animType) {
            case ANIM_NONE:
                drawNone(canvas);
                break;
            case ANIM_FADE:
                drawFade(canvas);
                break;
            case ANIN_ROTATE:
                drawRotate(canvas);
                break;
            case ANIM_ROLL:
                drawRoll(canvas);
                break;
            case ANIM_RIGHT:
                drawRight(canvas);
                break;
            case ANIM_UP:
                drawUp(canvas);
                break;
            case ANIM_BOTTOM_UP:
                drawBottomUp(canvas);
                break;
            case ANIM_SCALE:
                drawScal(canvas);
                break;
            case ANIM_SCALE2:
                drawScal2(canvas);
                break;
            case ANIM_CRASH:
                drawCrash(canvas);
                break;
            case ANIM_JUMP:
                drawJump(canvas);
                break;
        }
    }

    /**
     * 播放gif: 直接用movie绘制闪退?
     * 使用读帧方式,绘制每帧
     */
    private void drawGif(Canvas canvas) {
        if (movie != null) {
            long now = System.currentTimeMillis();
            if (gifPlayTime == 0) {
                gifPlayTime = now;
            }

            int dur = movie.duration();
            if (dur <= 0) {
                gifPlayTime = 0;
                Log.w(TAG, "Gif 读取失败|文件有问题,仅画一次");
                drawNone(canvas);
                return;
            }

            int relTime = (int) ((now - gifPlayTime) % dur);
            Drawable drawable = getMovieFirstFrame(movie, relTime);
            if (drawable != null) {
                drawable.setBounds(0, 0, width, height);
                drawable.draw(canvas);
            } else {
                canvas.drawColor(Color.WHITE);
            }

            invalidate();
        }
    }

    //无动画
    private void drawNone(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawNone: error -- " + curIndex);
            return;
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex].setBounds(0, 0, width, height);
            drawables[curIndex].draw(canvas);
        }
    }

    private void drawFade(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawFade: error -- " + curIndex);
            return;
        }
        //如果有上一张,先消失,再加载当前的
        if (curIndex == 0) {
            if (drawables[1] == null) {
                //第一张图
                drawables[curIndex].setBounds(0, 0, width, height);
                drawables[curIndex].setAlpha(alphaCur);
                drawables[curIndex].draw(canvas);
            } else {
                if (isSecond) {
                    if (drawables[curIndex] != null) {
                        drawables[curIndex].setBounds(0, 0, width, height);
                        drawables[curIndex].setAlpha(alphaCur);
                        drawables[curIndex].draw(canvas);
                    }
                } else {
                    //上一张,先消失
                    drawables[1].setBounds(0, 0, width, height);
                    drawables[1].setAlpha(alphaLast);
                    drawables[1].draw(canvas);
                }
            }
        } else {
            if (isSecond) {
                if (drawables[curIndex] != null) {
                    drawables[curIndex].setBounds(0, 0, width, height);
                    drawables[curIndex].setAlpha(alphaCur);
                    drawables[curIndex].draw(canvas);
                }
            } else {
                //上一张,先消失
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, 0, width, height);
                    drawables[0].setAlpha(alphaLast);
                    drawables[0].draw(canvas);
                }
            }
        }
    }

    /**
     * 顺时针旋转 180°
     * 仅顶部,底下不变
     */
    private void drawRotate(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawFade: error -- " + curIndex);
            return;
        }

        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
                drawables[curIndex].draw(canvas);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(0, 0, width, height);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, 0, width, height);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }

            if (drawables[curIndex] != null) {
                canvas.save();
                canvas.rotate(rotate, cX, cY);
                drawables[curIndex].draw(canvas);
                canvas.restore();
            }
        }
    }

    /**
     * 顺时针旋转90°
     * 仅顶部,底下不变
     */
    private void drawRoll(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawFade: error -- " + curIndex);
            return;
        }

        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
                drawables[curIndex].draw(canvas);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(0, 0, width, height);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, 0, width, height);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }

            if (drawables[curIndex] != null) {
                canvas.save();
                canvas.rotate(rotate, cX, cY);
                drawables[curIndex].draw(canvas);
                canvas.restore();
            }
        }
    }

    /**
     * 右进左出:进入时由变不变(宽度慢慢变大),出去时保持宽度不变
     */
    private void drawRight(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawRight: error -- " + curIndex);
            return;
        }
        //如果有上一张,先消失,再加载当前的
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(leftLast, 0, width + leftLast, height);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(leftLast, 0, width + leftLast, height);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(leftCur, 0, width, height);
            }
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex].draw(canvas);
        }
    }

    /**
     * 从下面上浮:进入时由变不变(高度慢慢变大),出去时保持高度不变
     */
    private void drawUp(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawRight: error -- " + curIndex);
            return;
        }
        //如果有上一张,先消失,再加载当前的
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(0, topLast, width, height - topLast);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, topLast, width, height - topLast);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, topCur, width, height);
            }
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex].draw(canvas);
        }
    }

    /**
     * 底部往上走,上一张不动
     * 图片大小不变
     */
    private void drawBottomUp(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawRight: error -- " + curIndex);
            return;
        }
        //如果有上一张,先消失,再加载当前的
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(0, 0, width, height);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, 0, width, height);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        }

        if (drawables[curIndex] != null) {
            canvas.save();
            canvas.translate(0, topCur);
            drawables[curIndex].draw(canvas);
            canvas.restore();
        }
    }

    private void drawScal(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawScal: error -- " + curIndex);
            return;
        }
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(rectLast);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(rectLast);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(rectCur);
            }
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex].draw(canvas);
        }
    }

    /**
     * 仅当前图片慢慢变大, 上一张不变
     */
    private void drawScal2(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawScal: error -- " + curIndex);
            return;
        }
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
            }
        } else {
            if (curIndex == 0) {
                if (drawables[1] != null) {
                    //上一张
                    drawables[1].setBounds(0, 0, width, height);
                    drawables[1].draw(canvas);
                }
            } else {
                //上一张
                if (drawables[0] != null) {
                    drawables[0].setBounds(0, 0, width, height);
                    drawables[0].draw(canvas);
                }
            }

            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(rectCur);
            }
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex].draw(canvas);
        }
    }

    private void drawCrash(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawCrash: error -- " + curIndex);
            return;
        }
        if (isOver) {
            //动画结束
            if (drawables[curIndex] != null) {
                drawables[curIndex].setBounds(0, 0, width, height);
                drawables[curIndex].draw(canvas);
            }
        } else {
            for (CubeBean item : pixelList) {
                if (item.sY > height) {
                    //超出容器不用画
                    continue;
                }
                paint.setColor(item.color);
                canvas.drawRect(item.sX, item.sY, item.sX + item.cL, item.sY + item.cL, paint);

                //变化 s = v0t + at^2
                item.sY += (float) (item.vY * time + item.aY * Math.pow(time, 2));
            }
        }
    }

    private void drawJump(Canvas canvas) {
        if (curIndex < 0) {
            Log.e(TAG, "drawJump: error -- " + curIndex);
            return;
        }
        //当前图片一直存在
        if (drawables[curIndex] != null) {
            drawables[curIndex].setBounds(0, 0, width, height);
            drawables[curIndex].draw(canvas);
        }

        if (isOver) {
            return;
        }

        //上一张图
        if (curIndex == 0) {
            if (drawables[1] != null) {
                //上一张
                drawables[1].setBounds(rectJump);
                drawables[1].draw(canvas);
            }
        } else {
            //上一张
            if (drawables[0] != null) {
                drawables[0].setBounds(rectJump);
                drawables[0].draw(canvas);
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        releaseBase();
        super.onDetachedFromWindow();
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (isGif) {
            if (visibility == VISIBLE) {
                invalidate();
            }
        }
    }
    

    /**
     * 获取Gif图片帧
     */
    private Drawable getMovieFirstFrame(Movie movie, int time) {
        if (movie == null) {
            return null;
        }
        Bitmap bitmap = Bitmap.createBitmap(movie.width(), movie.height(),
                Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        movie.setTime(time);
        movie.draw(canvas, 0, 0);
        canvas.save();
        return new BitmapDrawable(getResources(), bitmap);
    }

    /**
     * 大于控件分辨率的图片会自动压缩
     *
     * @param filePath 图片路径
     * @return Drawable
     */
    private Drawable getDrawableFromFile(String filePath) {
        //启用缓存
        if (cacheMap == null) {
            cacheMap = new HashMap<>();
        } else {
            if (cacheMap.containsKey(filePath)) {
                return cacheMap.get(filePath);
            }
        }

        Drawable drawable = null;

        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            //设置为true,仅解析图片的原始宽高信息,并不会加载图片
            options.inJustDecodeBounds = true;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            BitmapFactory.decodeFile(filePath, options);

            //按控件宽高压缩
            options.inSampleSize = calculateInSampleSize(options, width, height);
            options.inJustDecodeBounds = false;

            if (options.inSampleSize > 0) {
                drawable = new BitmapDrawable(getResources(), BitmapFactory.decodeFile(filePath, options));
                if (cacheMap.size() < MAX_CACHE) {
                    cacheMap.put(filePath, drawable);
                }//超出不处理
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return drawable;
    }

    /**
     * 计算出合适的图片倍率
     *
     * @param options:   图片bitmapFactory选项
     * @param reqWidth:  需要的图片宽
     * @param reqHeight: 需要的图片长
     * @return int 成功返回倍率, 异常-1
     */
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        int inSampleSize;
        try {
            // reqWidth/width, reqHeight/height两者中最大值作为压缩比
            inSampleSize = Math.max(options.outWidth / reqWidth, options.outHeight / reqHeight);
            inSampleSize = Math.max(inSampleSize, 1);//小图不变
        } catch (Exception ignored) {
            return -1;
        }
        return inSampleSize;
    }

    protected void cancelAnim() {
        if (animator != null) {
            animator.removeAllListeners();
            animator.end();
            animator = null;
        }
    }

    private void doAnimation() {
        if (animator != null) {
            animator.removeAllListeners();
        }

        if (isRandom) {
            animType = (int) (Math.random() * 1000) % ANIM_NUM;
            resetAnimator();
        }
        if (animType == ANIM_NONE || animator == null) {
            //无动画
            invalidate();
            return;
        } else if (animType == ANIM_CRASH) {
            pixelList.clear();
            //获取上一张图片的像素
            BitmapDrawable bitmapDrawable = null;
            if (curIndex == 0) {
                bitmapDrawable = (BitmapDrawable) drawables[1];
            } else if (curIndex == 1) {
                bitmapDrawable = (BitmapDrawable) drawables[0];
            }
            if (bitmapDrawable == null) {
                isOver = true;
                invalidate();
                return;
            }

            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null) {
                //该参数控制原来每一个像素点在屏幕上的缩放比例,此时为放大两倍
                //基于控件宽高, 获取等比缩放下对应的像素点
                float rW = bitmap.getWidth() * 1f / width;
                float rH = bitmap.getHeight() * 1f / height;
                CubeBean item;
                for (int i = 0; i < width; i += LENTH) {//像素跨值
                    for (int j = 0; j < height; j += LENTH) {
                        item = new CubeBean();
                        item.color = bitmap.getPixel((int) (i * rW), (int) (j * rH));//取样点

                        item.sX = i;
                        item.sY = j;
                        item.cL = LENTH;

                        //初始速度
                        item.vY = getRandom(3, 20);
                        //加速度
                        item.aY = 15f;//9.8f;

                        pixelList.add(item);
                    }
                }
            }
        }

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                time = 0;
                isSecond = false;
                isOver = false;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                time = 0;
                isOver = true;
                invalidate();
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                //
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                //
            }
        });

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int av = (int) animation.getAnimatedValue();
                switch (animType) {
                    case ANIM_FADE:
                        if (av > CV / 2) {//一半
                            isSecond = true;
                        }
                        alphaCur = av;
                        alphaLast = CV - av;
                        break;
                    case ANIN_ROTATE:
                        rotate = MAX_GRADE + av;
                        break;
                    case ANIM_ROLL:
                        rotate = MAX_GRADE + av;
                        break;
                    case ANIM_RIGHT:
                        leftLast = -av - 10;//增加两图之间间隔
                        leftCur = CV - av;
                        break;
                    case ANIM_UP:
                        topLast = -av - 10;//增加两图之间间隔
                        topCur = CV - av;
                        break;
                    case ANIM_BOTTOM_UP:
                        topCur = CV - av;
                        break;
                    case ANIM_SCALE:
                        if (av > CV / 2) {//一半
                            isSecond = true;
                        }

                        if (!isSecond) {
                            //后面不用变化上一张 变小
                            rectLast.left = av;
                            rectLast.top = (int) (av / whRate);
                            rectLast.right = width - av;
                            rectLast.bottom = height - rectLast.top;
                        }

                        //当前:变大
                        rectCur.left = CV - av;
                        rectCur.top = (int) (rectCur.left / whRate);
                        rectCur.right = CV + av;
                        rectCur.bottom = height - rectCur.top;
                        break;
                    case ANIM_SCALE2:
                        //当前:变大
                        rectCur.left = CV - av;
                        rectCur.top = (int) (rectCur.left / whRate);
                        rectCur.right = CV + av;
                        rectCur.bottom = height - rectCur.top;
                        break;
                    case ANIM_CRASH:
                        time = animation.getCurrentPlayTime() / 1000f;//ms
                        break;
                    case ANIM_JUMP:
                        if (curIndex == 0) {
                            //右出
                            if (av < JUMP_THRESHOLD) {
                                //先向左移动
                                rectJump.left = -av;
                            } else {
                                //向右跳出
                                rectJump.left = av - JUMP_THRESHOLD;
                            }
                        } else {
                            //左出
                            if (av < JUMP_THRESHOLD) {
                                //先向左移动
                                rectJump.left = av;
                            } else {
                                //向右跳出
                                rectJump.left = JUMP_THRESHOLD - av;
                            }
                        }

                        rectJump.right = width + rectJump.left;
                        rectJump.top = 0;
                        rectJump.bottom = height;
                        break;
                }

                invalidate();
            }
        });
        animator.start();
    }

    private float getRandom(int a, int b) {
        return (float) (Math.random() * (b - a) + a);
    }

    

    /**
     * 设置动画类型
     */
    public void setAnimType(int animType) {
        if (animType >= ANIM_NUM) {
            //随机
            this.isRandom = true;
            return;
        }
        this.animType = animType;
        resetAnimator();
    }

    /**
     * 设置图片路径,默认路径存在(外部校验)
     *
     * @param path 图片路径
     */
    public boolean setImageResource(String path) {
        if (TextUtils.isEmpty(path)) {
            return false;
        }

        if (path.equals(lastPath)) {
            Log.d(TAG, "相同图片, 不切换!");
            return true;
        } else {
            lastPath = path;
        }

        if (path.endsWith(".gif")) {
            isGif = true;
            movie = Movie.decodeFile(path);
            return setImageResource(getMovieFirstFrame(movie, 500), path);
        } else {
            isGif = false;
            return setImageResource(getDrawableFromFile(path), path);
        }
    }

    /**
     * 设置图片
     */
    public boolean setImageResource(@DrawableRes int resId) {
        Drawable d;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            d = context.getDrawable(resId);
        } else {
            d = context.getResources().getDrawable(resId);
        }

        return setImageResource(d, String.valueOf(resId));
    }

    /**
     * 设置图片
     *
     * @return 是否成功播放
     */
    public boolean setImageResource(Drawable drawable, String msg) {
        if (drawable == null) {
            Log.e(TAG, "图片资源为空!" + msg);
            return false;
        }

        //重置透明度
        drawable.setAlpha(MAX_ALPHA);
        if (drawables == null) {
            drawables = new Drawable[2];
        }

        curIndex++;//def -1

        if (curIndex > 1) {
            curIndex = 0;
        }

        if (drawables[curIndex] != null) {
            drawables[curIndex] = null;//回收
        }

        drawables[curIndex] = drawable;

        //Animators may only be run on Looper threads
        if (isGif) {
            //gif 文件直接播放,不用动画
            invalidate();
        } else {
            doAnimation();
        }
        return true;
    }

    public void releaseBase() {
        cancelAnim();
        isGif = false;
        movie = null;
        lastPath = null;
        drawables = null;
        curIndex = -1;
        gifPlayTime = 0;
        if (cacheMap != null) {
            cacheMap.clear();
            cacheMap = null;
        }
        if (pixelList != null) {
            pixelList.clear();
            pixelList = null;
        }
    }
}
相关推荐
rocpp8 小时前
Android 相册选择与拍照接入实践:MediaStore 分页、权限适配与 FileProvider
android
Flynt8 小时前
升级Flutter 3.44,我踩了HCPP和AGP 9的坑
android·flutter·dart
白色牙膏9 小时前
Cocos Creator 2.4.x 接入 AdMob 插件的迁移实践
android
我命由我1234511 小时前
C++ - 面向对象 - 常成员函数
android·java·linux·c语言·开发语言·c++·算法
tryqaaa_11 小时前
学习日志(四)【php反序列化魔术方法以及pop构造配实战】
android
Java小学生丶13 小时前
记录一下我的 Gradle 开发环境配置过程
android·java·gradle·maven·安卓
问心无愧051314 小时前
ctf show web 入门256
android·前端·笔记
霸道流氓气质14 小时前
MySQL 索引设计实战指南
android·数据库·mysql
R语言爱好者14 小时前
叠氮酸介绍
android
方白羽14 小时前
Android WebView 中实现第三方 QQ 登录的架构与流程详解
android·app