Android自定义DrawingView代码工作原理解析求助
Android自定义DrawingView代码全解析
原始代码
class DrawingView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) { private lateinit var mDrawPath: FingerPath private lateinit var mCanvasBitmap: Bitmap private lateinit var mCanvasPaint: Paint private lateinit var mDrawPaint: Paint private var mBrushSize = 0 private var color = Color.BLACK private lateinit var canvas: Canvas init { setUpDrawing() } private fun setUpDrawing() { mDrawPaint = Paint() mDrawPath = FingerPath(color, mBrushSize.toFloat()) mDrawPaint.color = color mDrawPaint.style = Paint.Style.STROKE mDrawPaint.strokeJoin = Paint.Join.ROUND mDrawPaint.strokeCap = Paint.Cap.ROUND mCanvasPaint = Paint(Paint.DITHER_FLAG) mBrushSize = 20 } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) mCanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888) canvas = Canvas(mCanvasBitmap) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawBitmap(mCanvasBitmap, 0f, 0f, mDrawPaint) if (!mDrawPath.isEmpty) { mDrawPaint.strokeWidth = mDrawPath.brushThickness mDrawPaint.color = mDrawPath.color canvas.drawPath(mDrawPath, mDrawPaint) } } override fun onTouchEvent(event: MotionEvent?): Boolean { val touchX = event?.x val touchY = event?.y when (event?.action) { MotionEvent.ACTION_DOWN -> { mDrawPath.color = color mDrawPath.brushThickness = mBrushSize.toFloat() mDrawPath.reset() mDrawPath.moveTo(touchX!!, touchY!!) } MotionEvent.ACTION_MOVE -> { mDrawPath.lineTo(touchX!!, touchY!!) } MotionEvent.ACTION_UP -> { mDrawPath = FingerPath(color, mBrushSize.toFloat()) } else -> return false } invalidate() return true } internal inner class FingerPath(var color: Int, var brushThickness: Float) : Path() }
用户问题
我正在学习Android开发课程,讲师正在开发一款绘图应用,但他未解释代码中变量的用途、重写函数的原因,导致我无法理解这段自定义DrawingView代码的工作机制,恳请帮忙解析其运行逻辑。
一、核心变量含义
mDrawPath: 继承自Android原生Path的自定义类实例,不仅记录手指绘制的轨迹路径,还携带当前路径的颜色、画笔粗细信息。mCanvasBitmap: 离屏Bitmap,作为"绘制底图"保存所有已完成的绘制内容,避免每次重绘都重复绘制历史路径。mCanvasPaint: 开启了DITHER_FLAG的画笔,用于优化Bitmap绘制时的颜色抖动效果,让色彩过渡更平滑。mDrawPaint: 实际绘制路径的画笔,控制线条的颜色、粗细、端点/拐角样式。mBrushSize: 画笔粗细的数值,默认设为20。color: 当前画笔的颜色,默认黑色。canvas: 绑定到mCanvasBitmap的画布对象,专门用来将完成的绘制内容持久化到底图上。
二、重写核心函数的作用
1. onSizeChanged
当View尺寸发生变化(首次加载、屏幕旋转等场景)时自动调用。这里用来创建与View尺寸完全匹配的mCanvasBitmap,并绑定对应的Canvas,确保绘制区域和View可视区域完全对齐。
2. onDraw
View的核心渲染方法,系统在需要刷新界面时自动调用:
- 第一步绘制
mCanvasBitmap,把历史绘制内容显示出来,保证之前画的线条不会丢失; - 第二步如果当前有未完成的绘制路径(手指还在画),就用
mDrawPaint把这条实时路径画到View画布上,让用户看到正在绘制的线条。
3. onTouchEvent
处理用户触摸交互,是绘图功能的核心逻辑:
ACTION_DOWN: 手指按下时,重置当前路径,将路径起点定位到触摸坐标,同时同步当前的画笔颜色和粗细;ACTION_MOVE: 手指移动时,不断给路径添加线段,记录完整的移动轨迹;ACTION_UP: 手指抬起时,创建新的FingerPath实例,准备下一次绘制;- 每次处理完触摸事件后调用
invalidate(),触发onDraw刷新界面,实时显示绘制效果。
三、整体运行流程
- 初始化阶段: View创建时执行
init块,调用setUpDrawing初始化画笔、路径对象,设置默认的画笔样式(圆角端点/拐角、描边模式)、粗细和颜色。 - 尺寸确定: View尺寸确定后,
onSizeChanged创建对应大小的底图Bitmap和绑定的Canvas。 - 触摸交互:
- 手指按下:初始化当前绘制路径,记录起点;
- 手指移动:扩展路径并触发界面刷新,实时显示当前线条;
- 手指抬起:重置路径,准备下一次绘制;
- 渲染显示: 每次刷新时先绘制历史底图,再绘制当前未完成的路径,实现"实时绘制+历史保留"的效果。
代码缺陷说明
这段代码存在一个关键问题:手指抬起时,当前绘制的路径没有被画到mCanvasBitmap上,导致抬起后线条会消失。正确的做法是在ACTION_UP时将路径持久化到底图:
MotionEvent.ACTION_UP -> { canvas.drawPath(mDrawPath, mDrawPaint) mDrawPath = FingerPath(color, mBrushSize.toFloat()) }
内容的提问来源于stack exchange,提问作者Ionut
相关产品推荐
相关产品推荐

