Android设备方向切换时保持图片上手绘Path路径不偏移
Android屏幕旋转后手绘线条位置错位解决方案
问题根因
你当前存储的Path对象绑定了竖屏状态下View的像素坐标系,设备旋转后Activity重建、绘图View的宽高尺寸、坐标系映射关系完全改变,直接用旧像素坐标绘制必然出现位置偏移。靠配置configChanges屏蔽Activity重建的野路子无法覆盖折叠屏、多窗口分屏、显示尺寸调整等所有会触发View尺寸变化的场景,不推荐使用。
核心解决思路
放弃直接存储绑定固定像素值的Path,所有手绘点位统一转换为相对于绘图区域的0~1区间归一化比例坐标存储。每次View尺寸因旋转、分屏等场景发生变化时,根据当前最新的View宽高,将比例坐标重新换算为对应像素值,重新生成绘制用的Path即可保证位置完全匹配。
具体实现步骤
- 替换原有纯
Path的存储结构,新建笔画数据类存储归一化点位
触摸绘制过程中,不要直接往绘制用// 单条手绘线的属性数据 data class DrawStroke( val paintColor: Int, val strokeWidthPx: Float, // 存储0~1之间的比例坐标,不绑定固定像素 val pointList: MutableList<PointF> = mutableListOf() )Path里塞像素坐标,实时将触摸点的像素坐标转换为比例值存入对应DrawStroke对象:override fun onTouchEvent(event: MotionEvent): Boolean { when(event.action) { MotionEvent.ACTION_DOWN -> { currentStroke = DrawStroke(currentPaintColor, currentStrokeWidth) // 转比例坐标:当前x/绘图控件总宽,当前y/绘图控件总高 val ratioX = event.x / width.toFloat() val ratioY = event.y / height.toFloat() currentStroke.pointList.add(PointF(ratioX, ratioY)) } MotionEvent.ACTION_MOVE -> { val ratioX = event.x / width.toFloat() val ratioY = event.y / height.toFloat() currentStroke.pointList.add(PointF(ratioX, ratioY)) // 实时绘制当前笔画逻辑... invalidate() } MotionEvent.ACTION_UP -> { allStrokes.add(currentStroke) } } return true } - 重写绘图View的
onSizeChanged回调,尺寸变化后全量重绘所有笔画
所有会触发View宽高改变的场景(旋转、折叠屏展开、分屏调整大小)都会触发该回调,在这里清空旧的绘制Path,用新的宽高把所有存储的比例坐标转回实时像素,重新构建绘制路径:override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) // 清空旧的像素路径 drawPath.reset() // 遍历所有已存储的笔画,重新换算坐标生成新路径 allStrokes.forEach { stroke -> val strokePath = Path() stroke.pointList.forEachIndexed { index, pointRatio -> val realX = pointRatio.x * w val realY = pointRatio.y * h if (index == 0) strokePath.moveTo(realX, realY) else strokePath.lineTo(realX, realY) } drawPath.addPath(strokePath) } invalidate() } - 做好配置变更下的数据留存
推荐将存储所有笔画的allStrokes列表放在ViewModel中持有,横竖屏重建时数据不会丢失;如果项目没引入ViewModel组件,也可以通过重写onSaveInstanceState将笔画数据序列化后存入Bundle,在重建时恢复数据。
注意事项
如果你的手绘是覆盖在做了缩放适配的图片上(比如用了CenterCrop、FitCenter缩放模式),换算比例时不要直接用整个View的宽高,要先计算出图片实际在View中展示的矩形区域的左上坐标、真实宽高,基于这个矩形区域做坐标换算,否则图片本身的缩放偏移也会导致线条错位。
不要在Manifest中给Activity添加android:configChanges="orientation|screenSize"试图拦截系统重建,该方式无法覆盖所有尺寸变化场景,后续适配成本极高。
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

