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;
        }
    }
}
相关推荐
建群新人小猿9 分钟前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神1 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛1 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法2 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter3 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快4 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl5 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
麦田里的守望者江5 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
Dnelic-5 小时前
解决 Android 单元测试 No tests found for given includes:
android·junit·单元测试·问题记录·自学笔记
佛系小嘟嘟6 小时前
Android Studio不显示需要的tag日志解决办法《All logs entries are hidden by the filter》
android·ide·android studio