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;}}
}