Android屏幕旋转时自定义ImageView Canvas绘制内容后置、多次旋转丢失问题
自定义ImageView屏幕旋转绘制异常解决方案
现有代码核心问题
- 滥用静态修饰符修饰
drawPath、paintColor,View旋转重建时多实例共享状态导致逻辑错乱 onSizeChanged方法每次旋转直接创建空白canvasBitmap,原有绘制内容被直接覆盖- 路径使用View绝对坐标存储,未与底层图片做相对坐标绑定,旋转后View宽高互换导致绘制偏移
- 冗余逻辑
setVariables中重复调用setupDrawing()重置画笔参数,导致绘制状态丢失 onDraw中存在无用的旋转、save/restore逻辑,绘制顺序混乱导致内容被覆盖
修复步骤
1. 移除错误的静态修饰符
静态变量会导致多个View实例共享状态,旋转重建后状态冲突,直接删除相关变量的static修饰:
//drawing path CustomPath drawPath; //initial color int paintColor = 0xFF000000;
2. 优化onSizeChanged保留原有绘制内容
旋转后View尺寸变化时,不要直接创建空白Bitmap,将原有绘制内容缩放适配新尺寸:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Bitmap oldBitmap = canvasBitmap; // 创建新尺寸的Bitmap canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); drawCanvas = new Canvas(canvasBitmap); if (oldBitmap != null && !oldBitmap.isRecycled()) { // 把旧的绘制内容缩放后绘制到新Bitmap上 Matrix scaleMatrix = new Matrix(); scaleMatrix.postScale((float)w / oldBitmap.getWidth(), (float)h / oldBitmap.getHeight()); drawCanvas.drawBitmap(oldBitmap, scaleMatrix, canvasPaint); oldBitmap.recycle(); } heightB = h; wieghtB = w; }
3. 绑定绘制内容与图片相对坐标(解决偏移问题)
将触摸坐标转换为底层图片的比例坐标(取值范围0~1),不管View尺寸怎么变,绘制内容永远对应图片的同一位置:
// 新增方法:把View触摸坐标转为图片相对比例坐标 private float[] convertToImageRelative(float touchX, float touchY) { float[] point = new float[2]; Matrix inverseMatrix = new Matrix(); // 获取ImageView图片变换矩阵的反转矩阵,计算触摸点对应图片的原始坐标 getImageMatrix().invert(inverseMatrix); point[0] = touchX; point[1] = touchY; inverseMatrix.mapPoints(point); // 转换为0~1的比例值,适配所有尺寸场景 Drawable imgDrawable = getDrawable(); if (imgDrawable != null) { point[0] = point[0] / imgDrawable.getIntrinsicWidth(); point[1] = point[1] / imgDrawable.getIntrinsicHeight(); } return point; } // 新增方法:把图片相对比例坐标转回当前View的实际绘制坐标 private float[] convertToViewCoordinate(float relativeX, float relativeY) { float[] point = new float[2]; Drawable imgDrawable = getDrawable(); if (imgDrawable != null) { point[0] = relativeX * imgDrawable.getIntrinsicWidth(); point[1] = relativeY * imgDrawable.getIntrinsicHeight(); getImageMatrix().mapPoints(point); } return point; }
触摸事件和路径存储全部基于比例坐标处理,绘制时再转换为当前View的实际坐标即可。
4. 清理冗余逻辑修复onDraw
删除cc相关的无用逻辑,统一绘制顺序保证内容层级正确:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 先绘制底层图片 canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); // 再绘制已完成的绘制内容 canvas.drawPath(drawPath, drawPaint); // 最后绘制正在编辑的路径 }
同时删除setVariables方法中重复调用的setupDrawing(),避免画笔状态被意外重置。
5. 可选优化(避免Activity重建)
如果业务场景允许,直接在Manifest对应的Activity节点添加配置,旋转时不重建Activity,从根源避免状态丢失问题:
<activity android:name=".YourTargetActivity" android:configChanges="orientation|screenSize|screenLayout" />
内容的提问来源于stack exchange,提问作者RR_Pradhan
相关产品推荐
相关产品推荐

