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开发的课程,讲师正在开发一个绘图应用程序--我不明白代码是如何工作的,因为他没有解释“为什么”;所以他输入了很多代码却没有解释为什么要使用那个变量或者为什么要覆盖那些函数;因此,我不明白代码是如何工作的。你能帮助我理解这段代码是如何工作的吗?
3条答案
按热度按时间aydmsdu91#
nbysray52#
此代码为Android中用于绘图的自定义视图类,该类扩展了View类,实现了touch事件处理,允许用户在屏幕上绘图。
该类定义了示例变量,用于存放绘图时使用的paint、path、bitmap和canvas,还包含了brush size和color的变量。
在
setUpDrawing
方法中,设置用于绘制的paint对象和用于跟踪用户触摸的path对象;在onSizeChanged
中,创建bitmap对象,并初始化其canvas对象;在onDraw
中,在屏幕上绘制canvas,如果不为空,则在画布上绘制path。onTouchEvent
方法处理触摸事件***(DOWN,MOVE,UP)并相应地更新path*。FingerPath
内部类扩展Path
类并包含path的颜色和**画笔大小 *。brjng4g33#
您是否已通读文档的此部分?Custom View Components
它解释了创建自定义视图的基础知识,这在基本层面上意味着覆盖
onDraw
(在那里你可以绘制视图的内容),或者onSizeChanged
(在那里你可以被告知视图有多大--也许你想设置画笔的粗细,计算出视图的中心位置等等)。onTouchEvent
更高级一点,它允许处理用户戳视图--上面的链接会进入视图,但如果您阅读touch gestures部分,您会有更好的理解。从广义上讲,您可以通过onTouchEvent
获得有关交互事件的信息,并计算出用户是否触摸了视图,移动了手指,举起它或将它移出边界等。你可以使用这些信息,比如说,在用户的手指下为绘画应用程序绘制东西。Canvas
是Bitmap
的一个绘图接口。你不必计算出哪些像素要改变成什么颜色来画一条线或其他什么,你可以通过一个 Package 了Bitmap
的Canvas
来完成所有的绘图。这让你可以抽象这个过程,做一些高级的事情,比如“画一条线”,“画一条弧”,“画这整个路径”,“渲染此文本”等等。Canvas
计算出如何在Bitmap
的像素数组中实现这一点。绘图通过
Paint
s进行,您可以将其视为一个表示“如何”绘图的对象。绘制线条看起来像什么?您使用的Paint
定义了笔划宽度、透明度、颜色等--就像画图程序中的工具选项。它还允许你设置文本大小等(如果你用它来渲染文本),并做一些有趣的事情,比如混合它所绘制的像素,创建着色器等等。如果你用位图作为源图像,它还可以做一些像控制平铺这样的事情。一般来说,你会希望在启动时创建这些
Paint
,并在View
的生命周期中重用它们,所以通常会有几个-一个用于绘制背景,一个用于绘制曲线,一个用于渲染文本等。通常在
onDraw
中,你只需要绘制当前状态的视图。该方法需要一个Canvas
参数--这就是你如何绘制UI上呈现的实际位图。所以如果你有一个旋钮,你可以绘制圆,在适当的位置绘制位置指示器,添加任何文本,然后你就完成了!对于绘图应用程序来说,这就有点复杂了--你需要记住并绘制的“状态”是所有已经发生的绘图操作的总和。(创建撤消级别),但最简单的方法是创建自己的
Bitmap
来存储当前绘图。您可以将其 Package 在自己的Canvas
中(这样你就可以在上面画图),然后所有的用户交互都把东西画到Canvas
上,所以你是在位图上画图。然后,在onDraw
中,你基本上只需要把位图的内容画到系统提供的Canvas
上,这样它就可以画在屏幕上--基本上只是显示你所拥有的。这里的代码有点奇怪--内部位图(名为
mCanvasBitmap
)被封装在Canvas
(名为canvas
)中,但实际上从未绘制到它上面。我觉得这行代码应该是用来渲染使用触摸手势构建的Path
的:但是在
onDraw
的作用域中,canvas
是指被传入的参数,即用于绘制到屏幕的Canvas
,而不是包裹mCanvasBitmap
的那个。因此内部位图总是保持为空,然后画出最近的路径(这是一个观察你如何命名事物的很好的例子--为什么mCanvas
不保持一致呢?)它从来不会通过在你的内部位图上绘制路径来“构建”一个图像。我不知道代码的确切意图是什么,我只是想指出这一点!