kotlin 有人能给我解释一下这个自定义视图代码是如何工作的吗?

j13ufse2  于 2023-02-05  发布在  Kotlin
关注(0)|答案(3)|浏览(101)
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开发的课程,讲师正在开发一个绘图应用程序--我不明白代码是如何工作的,因为他没有解释“为什么”;所以他输入了很多代码却没有解释为什么要使用那个变量或者为什么要覆盖那些函数;因此,我不明白代码是如何工作的。你能帮助我理解这段代码是如何工作的吗?

aydmsdu9

aydmsdu91#

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 {
// init block will called first when instance will be created so we
// are calling method setUpDrawing() as it is initialising everything
// that required to draw like color , brush size , brush behaviour
// (round , stroke etc .. ) . in simple manner , we can say painter is
// collecting all required tools before starting to paint

        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

    }

 // this method is going to be called by system when size is going to be
// changed so we are here creating blank board on which we are going to
// draw
    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) // drawing path on canvas
        }
    }

// this method will be called by system when user is going to touch screen
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        val touchX = event?.x
        val touchY = event?.y

        when (event?.action) {
// this event will be fired when user put finger on screen
            MotionEvent.ACTION_DOWN -> { 
                mDrawPath.color = color
                mDrawPath.brushThickness = mBrushSize.toFloat()

                mDrawPath.reset() // reseting path before we set inital point
                mDrawPath.moveTo(touchX!!, touchY!!)// set point from where drawing will be started 
            }

// this event will be fired when user start to move it's fingure . this will be fired continually until user pickup fingure 
            MotionEvent.ACTION_MOVE -> {
                mDrawPath.lineTo(touchX!!, touchY!!)

            }
// this event will be fired when user will pick up fingure from screen
            MotionEvent.ACTION_UP -> {
                mDrawPath = FingerPath(color, mBrushSize.toFloat())
            }
            else -> return false
        }

        invalidate() / /refreshing layout to reflect drawing changes
        return true
    }

    internal inner class FingerPath(var color: Int, var brushThickness: Float) : Path()
}
nbysray5

nbysray52#

此代码为Android中用于绘图的自定义视图类,该类扩展了View类,实现了touch事件处理,允许用户在屏幕上绘图。
该类定义了示例变量,用于存放绘图时使用的paintpathbitmapcanvas,还包含了brush sizecolor的变量。
setUpDrawing方法中,设置用于绘制的paint对象和用于跟踪用户触摸的path对象;在onSizeChanged中,创建bitmap对象,并初始化其canvas对象;在onDraw中,在屏幕上绘制canvas,如果不为空,则在画布上绘制path
onTouchEvent方法处理触摸事件***(DOWN,MOVE,UP)并相应地更新path*。FingerPath内部类扩展Path类并包含path颜色和**画笔大小 *。

brjng4g3

brjng4g33#

您是否已通读文档的此部分?Custom View Components
它解释了创建自定义视图的基础知识,这在基本层面上意味着覆盖onDraw(在那里你可以绘制视图的内容),或者onSizeChanged(在那里你可以被告知视图有多大--也许你想设置画笔的粗细,计算出视图的中心位置等等)。
onTouchEvent更高级一点,它允许处理用户戳视图--上面的链接会进入视图,但如果您阅读touch gestures部分,您会有更好的理解。从广义上讲,您可以通过onTouchEvent获得有关交互事件的信息,并计算出用户是否触摸了视图,移动了手指,举起它或将它移出边界等。你可以使用这些信息,比如说,在用户的手指下为绘画应用程序绘制东西。
CanvasBitmap的一个绘图接口。你不必计算出哪些像素要改变成什么颜色来画一条线或其他什么,你可以通过一个 Package 了BitmapCanvas来完成所有的绘图。这让你可以抽象这个过程,做一些高级的事情,比如“画一条线”,“画一条弧”,“画这整个路径”,“渲染此文本”等等。Canvas计算出如何在Bitmap的像素数组中实现这一点。
绘图通过Paint s进行,您可以将其视为一个表示“如何”绘图的对象。绘制线条看起来像什么?您使用的Paint定义了笔划宽度、透明度、颜色等--就像画图程序中的工具选项。它还允许你设置文本大小等(如果你用它来渲染文本),并做一些有趣的事情,比如混合它所绘制的像素,创建着色器等等。如果你用位图作为源图像,它还可以做一些像控制平铺这样的事情。
一般来说,你会希望在启动时创建这些Paint,并在View的生命周期中重用它们,所以通常会有几个-一个用于绘制背景,一个用于绘制曲线,一个用于渲染文本等。
通常在onDraw中,你只需要绘制当前状态的视图。该方法需要一个Canvas参数--这就是你如何绘制UI上呈现的实际位图。所以如果你有一个旋钮,你可以绘制圆,在适当的位置绘制位置指示器,添加任何文本,然后你就完成了!
对于绘图应用程序来说,这就有点复杂了--你需要记住并绘制的“状态”是所有已经发生的绘图操作的总和。(创建撤消级别),但最简单的方法是创建自己的Bitmap来存储当前绘图。您可以将其 Package 在自己的Canvas中(这样你就可以在上面画图),然后所有的用户交互都把东西画到Canvas上,所以你是在位图上画图。然后,在onDraw中,你基本上只需要把位图的内容画到系统提供的Canvas上,这样它就可以画在屏幕上--基本上只是显示你所拥有的。
这里的代码有点奇怪--内部位图(名为mCanvasBitmap)被封装在Canvas(名为canvas)中,但实际上从未绘制到它上面。我觉得这行代码应该是用来渲染使用触摸手势构建的Path的:

override fun onDraw(canvas: Canvas) {
    ...
    if (!mDrawPath.isEmpty) {
        ...
        canvas.drawPath(mDrawPath, mDrawPaint) // drawing path on canvas
    }
}

但是在onDraw的作用域中,canvas是指被传入的参数,即用于绘制到屏幕的Canvas而不是包裹mCanvasBitmap的那个。因此内部位图总是保持为空,然后画出最近的路径(这是一个观察你如何命名事物的很好的例子--为什么mCanvas不保持一致呢?)它从来不会通过在你的内部位图上绘制路径来“构建”一个图像。我不知道代码的确切意图是什么,我只是想指出这一点!

相关问题