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

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

效果(录制的有点卡)

在这里插入图片描述
在这里插入图片描述

1. 引用:
    <com.nepalese.virgolib.widget.image.BaseImageViewandroid:id="@+id/base_image"android:layout_width="match_parent"android:layout_height="match_parent" />
2. 接口:
private BaseImageView baseImageView;
//绑定
baseImageView = findViewById(R.id.base_image);
//设置动画类型
baseImageView.setAnimType(type);
//设置图片资源
baseImageView.setImageResource(path);
3. BaseImageView.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|1private int CV;//线性变化的基础值private int JUMP_THRESHOLD;//跳动偏移阈值 pxprivate 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;}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (w > 0 && h > 0) {initLayout(w, h);}}@Overrideprotected 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^2item.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);}}}@Overrideprotected void onDetachedFromWindow() {releaseBase();super.onDetachedFromWindow();}@Overrideprotected 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() {@Overridepublic void onAnimationStart(Animator animation) {time = 0;isSecond = false;isOver = false;}@Overridepublic void onAnimationEnd(Animator animation) {time = 0;isOver = true;invalidate();}@Overridepublic void onAnimationCancel(Animator animation) {//}@Overridepublic void onAnimationRepeat(Animator animation) {//}});animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic 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;//msbreak;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 -1if (curIndex > 1) {curIndex = 0;}if (drawables[curIndex] != null) {drawables[curIndex] = null;//回收}drawables[curIndex] = drawable;//Animators may only be run on Looper threadsif (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;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/450043.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AD画图的使用

一、新建工程 二、绘制原理图 1、原理图搜索方法&#xff1a; https://www.ti.com/lit/ds/symlink/tlv1117.pdf?ts1729143086540&ref_urlhttps%253A%252F%252Fwww.mouser.tw%252F www.alldatasheet.com 2、绘图步骤&#xff1a; 注&#xff1a;管脚四点朝外

2024软考网络工程师笔记 - 第5章.无线通信网

文章目录 移动通信与 5G1️⃣移动通信2️⃣移动通信制式3️⃣5G 应用场景与关键技术 &#x1f551;WLAN 通信技术1️⃣WLAN 通信技术 &#x1f552;WLAN 频谱与信道&#xff08;高频考点&#xff09;1️⃣WLAN 网络分类2️⃣ISM频段3️⃣不重叠信道&#xff08;重点&#xff09…

uniapp 省、市、区、乡镇 数据层级选择插件 Ba-DataPicker

Ba-DataPicker 是一款uniapp数据层级选择弹窗插件。支持省市区乡四级&#xff1b;支持自定义数据。 支持省、市、区、乡镇四级支持自定义数据支持字母检索 截图展示 支持定制、本地包、源码等&#xff0c;有建议和需要&#xff0c;请点击文章结尾“Uniapp插件开发”联系我&am…

人脸识别-特征算法

文章目录 一、LBPH算法1.基本原理2.实现步骤3.代码实现 二、Eigenfaces算法1.特点2.代码实习 三、FisherFaces算法1.算法原理2.算法特点3.代码实现 四、总结 人脸识别特征识别器是数字信息发展中的一种生物特征识别技术&#xff0c;其核心在于通过特定的算法和技术手段&#xf…

代码随想录算法训练营第八天(1)|哈希表理论基础

文档讲解&#xff1a;代码随想录 难度&#xff1a;有一点 哈希表理论基础 哈希表 首先什么是哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff0…

指尖的无声告白,算法里的隐约温柔

公主请阅 1. 三数之和1. 题目说明示例 1示例 2示例 3 1.2 题目分析1.3 代码部分1.3 代码分析 2. 四数之和2.1 题目说明示例 1示例 2 2.2 题目分析2.3 代码部分2.4 代码解析 1. 三数之和 题目传送门 1. 题目说明 给定一个整数数组 nums&#xff0c;判断数组中是否存在三个元素 …

鸿道Intewell操作系统构型介绍之Intewell-C全实时构型

鸿道(Intewell)操作系统主要包括Intewell-C、Intewell-H和Intewell-V三种不同构型产品&#xff1a; Intewell-C Intewell-C是一款工业实时微内核操作系统&#xff0c;由科东软件自主研发&#xff0c;具有超低延迟和最小抖动&#xff0c;保障工业设备可以高效处理时间敏感的现…

python爬虫实战案例——从移动端接口抓取微博评论,采用cookie登陆,数据存入excel表格,超详细(15)

文章目录 1、任务目标2、网页分析3、代码编写3.1 代码分析3.2 完整代码1、任务目标 1、目标网站:微博文章(https://m.weibo.cn/detail/4813628149072458),这是微博某一篇博文,用于本文测试 2、要求:爬取该博文下,所有一级评论和二级评论,以及每条评论的作者,最后保存至E…

熵权法计算评价指标权重——使用Excel VBA实现

[ 熵权法 ] 信息是系统有序程度的一个度量&#xff0c;熵是系统无序程度的一个度量&#xff1b;根据信息熵的定义&#xff0c;对于某项指标&#xff0c;可以用熵值来判断某个指标的离散程度&#xff0c;其信息熵值越小&#xff0c;指标的离散程度越大&#xff0c; 该指标对综合…

java脚手架系列4--测试用例、拦截器

异常处理、拦截器、数据库连接 1 测试用例 单元测试是一个老生常谈的问题&#xff0c;无论是后端对自己的代码质量把的第一道关也好&#xff0c;也是对测试减缓压力。这里就不过多讲述测试用例的重要性&#xff0c;但是有2个框架我们必须了解一下。 1.1 JUnit和mockito 我们…

gitlab保护分支设置

版本&#xff1a;gitlab10.2.2 一旦设置master分支被保护&#xff0c;除了管理员之外的任何用户都无法直接向master提交代码&#xff0c;只要提交代码就会报错 # git push -u origin master Total 0 (delta 0), reused 0 (delta 0) remote: GitLab: You are not allowed to pu…

[LeetCode] 733. 图像渲染

题目描述&#xff1a; 有一幅以 m x n 的二维整数数组表示的图画 image &#xff0c;其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sc 和 color 。你应该从像素 image[sr][sc] 开始对图像进行上色 填充 。 为了完成 上色工作&#xff1a; 从初始像素…

【python】OpenCV—Fun Mirrors

文章目录 1、准备工作2、原理介绍3、代码实现4、效果展示5、参考 1、准备工作 pip install vacm2、原理介绍 在OpenCV中&#xff0c;VCAM 库是一个用于简化创建三维曲面、定义虚拟摄像机、设置参数以及进行投影任务的工具。它特别适用于实现如哈哈镜等图像变形效果。 一、VC…

简易STL实现 | PriorityQueue 的实现

1、priority_queue 的底层是堆&#xff0c;标准库中 直接使用 std::make_heap, std::push_heap, std::pop_heap 来实现 priority_queue 2、std::make_heap、std::push_heap 和 std::pop_heap 这三个函数 用于 处理堆数据结构&#xff08;Heap&#xff09;。堆 是一种特殊的完全…

4、.Net 快速开发框架:DncZeus - 开源项目研究文章

DncZeus 是一个基于 ASP.NET Core 和 Vue.js 的前后端分离的通用后台管理系统框架&#xff0c;其愿景是成为一个易于使用且功能丰富的 .NET Core 通用后台权限管理模板系统基础框架。项目名称 "DncZeus" 由 "Dnc"(.NET Core 的缩写)和 "Zeus"(古…

JavaWeb环境下的Spring Boot在线考试系统开发

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于JavaWeb技术的在线考试系统设计与实现…

【学习】word保存图片

word中有想保存的照片 直接右键另存为的话&#xff0c;文件总是不清晰&#xff0c;截屏的话&#xff0c;好像也欠妥。 怎么办? 可以另存为 网页 .html 可以得到&#xff1a; 原图就放到了文件夹里面

Java学习Day47:戏耍黑手道人(项目记录)

1.项目背景 2.技术选择 3.环境搭建 1.创建空项目 创建health_parent父文件用来控制依赖&#xff0c;类型为quickStart 打包方式为&#xff0c;pom&#xff1a;用在父级工程或聚合工程中&#xff0c;用来做jar包的版本控制&#xff0c;必须指明这个聚合工程的打包方式为pom。…

计算机网络-RSTP工作过程与原理

前面我们已经学习了RSTP的一些基础概念以及对于STP的改进之处&#xff0c;因为RSTP兼容STP&#xff0c;所以实际上两者工作原理是一致的&#xff0c;这里只简单过一遍&#xff0c;然后进行一些基础实验即可&#xff0c;大致还是遵循选举根桥、确定端口角色与状态、全网收敛的思…

ROS理论与实践学习笔记——6 ROS机器人导航(仿真)之导航实现

准备工作&#xff1a;请先安装相关的ROS功能包 安装 gmapping 包(用于构建地图):sudo apt install ros-<ROS版本>-gmapping 安装地图服务包(用于保存与读取地图):sudo apt install ros-<ROS版本>-map-server 安装 navigation 包(用于定位以及路径规划):sudo apt in…