Rendering Inside onDraw(Canvas)

When your application is launched, all of its views are invalid. This means that they have not drawn anything to the screen. To fix this situation, Android calls the top-level View’s draw() function. This causes that view to draw itself, which causes its children to draw themselves. Those children’s children then draw themselves, and so on down the hierarchy. When all the views in the hierarchy have drawn themselves, the top-level View is no longer invalid.

You can also manually specify that a view is invalid, even if it is currently on the screen. This will cause the system to redraw the view with any necessary updates. You will mark the BoxDrawingView as invalid any time the user creates a new box or resizes a box by moving their finger. This will ensure that users can see what their boxes look like as they create them.

To hook into this drawing, you override the following View function:

    protected fun onDraw(canvas: Canvas)

The call to invalidate() that you make in response to ACTION_MOVE in onTouchEvent(MotionEvent) makes the BoxDrawingView invalid again. This causes it to redraw itself and will cause onDraw(Canvas) to be called again.

Now let’s consider the Canvas parameter. Canvas and Paint are the two main drawing classes in Android:

  • The Canvas class has all the drawing operations you perform. The functions you call on Canvas determine where and what you draw – a line, a circle, a word, or a rectangle.

  • The Paint class determines how these operations are done. The functions you call on Paint specify characteristics – whether shapes are filled, which font text is drawn in, and what color lines are.

In BoxDrawingView.kt, create two Paint objects when the BoxDrawingView is initialized.

Listing 30.6  Creating your paint (BoxDrawingView.kt)

class BoxDrawingView(context: Context, attrs: AttributeSet? = null) :
        View(context, attrs) {

    private var currentBox: Box? = null
    private val boxen = mutableListOf<Box>()
    private val boxPaint = Paint().apply {
        color = 0x22ff0000.toInt()
    }
    private val backgroundPaint = Paint().apply {
        color = 0xfff8efe0.toInt()
    }
    ...
}

Armed with paint, you can now draw your boxes to the screen.

Listing 30.7  Overriding onDraw(Canvas) (BoxDrawingView.kt)

class BoxDrawingView(context: Context, attrs: AttributeSet? = null) :
        View(context, attrs)
    ...
    override fun onDraw(canvas: Canvas) {
        // Fill the background
        canvas.drawPaint(backgroundPaint)

        boxen.forEach { box ->
            canvas.drawRect(box.left, box.top, box.right, box.bottom, boxPaint)
        }
    }
}

The first part of this code is straightforward: Using your off-white background paint, you fill the canvas with a backdrop for your boxes.

Then, for each box in your list of boxes, you determine what the left, right, top, and bottom of the box should be by looking at the two points for the box. The left and top values will be the minimum values, and the bottom and right values will be the maximum values.

After calculating these values, you call Canvas.drawRect(…) to draw a red rectangle onto the screen.

Run DragAndDraw and draw some red rectangles (Figure 30.4).

Figure 30.4  An expression of programmerly emotion

An expression of programmerly emotion

And that is it. You have now created a view that captures its own touch events and performs its own drawing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.162.87