Invalidate dirty rectangle with Hardware Acceleration

573 Views Asked by At

At this class i draw simple ground for Tic-Tae-Toe. It consists of intercepted lines and "X" in the center of the cell. So when User touches the cell, then textColor in it should be changed.

I use invalidate(rect) to redraw concrete cell, but in this case every cell changes it's textColor.

According to Romain Guy words, the canvas with whole view Rect comes for drawing. The DisplayList will find interceptions between drawing commands and your dirty Rect, and only those commands will be drawn. But seems, that it doesn't work so way. Partial invalidation in custom Android view with hardware acceleration

And also i found strange code change between 4.4 - 5.0 Android. So you can see, that mCurrentDirty disappeared from code at all. Android View.invalidate(Rect) different behavior between two devices

P.S for SA this logic works correctly, and only dirty Rect is changed.

package com.eugeneshapovalov.fizmigclient

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import timber.log.Timber

class TicTacToeView : View, View.OnTouchListener {

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    companion object {
        const val CELL_SIZE_RATIO = 1 / 3f
        const val LINE_SIZE = 2f
        const val CELL_COUNT = 3
    }

    val linePaint = Paint()
    val textPaint = Paint()
    val dirtyCell = Rect()
    var colorNumber: Int

    init {
        setOnTouchListener(this)

        colorNumber = 0
        linePaint.strokeWidth = resources.displayMetrics.density * LINE_SIZE
        textPaint.textSize = 60f
    }

    private lateinit var cells: Array<Array<Rect>>

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        initCells()
    }

    private fun initCells() {
        cells = Array(CELL_COUNT, { Array(CELL_COUNT, { Rect() }) })
        val xCell = (width * CELL_SIZE_RATIO).toInt()
        val yCell = (height * CELL_SIZE_RATIO).toInt()

        for (i in 0 until CELL_COUNT) {
            for (j in 0 until CELL_COUNT) {
                cells[i][j].left = (x + j * xCell).toInt()
                cells[i][j].top = (y + i * yCell).toInt()
                cells[i][j].right = (x + (j + 1) * xCell).toInt()
                cells[i][j].bottom = (y + (i + 1) * yCell).toInt()
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        drawLines(canvas)
        drawText(canvas)
    }

    private fun drawLines(canvas: Canvas) {
        // Vertical lines
        canvas.drawLine(x + width * CELL_SIZE_RATIO, y, x + width * CELL_SIZE_RATIO, y + height, linePaint)
        canvas.drawLine(x + width * 2 * CELL_SIZE_RATIO, y, x + width * 2 * CELL_SIZE_RATIO, y + height, linePaint)
        // Horizontal lines
        canvas.drawLine(x, y + height * CELL_SIZE_RATIO, x + width, y + height * CELL_SIZE_RATIO, linePaint)
        canvas.drawLine(x, y + height * 2 * CELL_SIZE_RATIO, x + width, y + height * 2 * CELL_SIZE_RATIO, linePaint)
    }

    private fun drawText(canvas: Canvas) {
        textPaint.color = when (colorNumber % 5) {
            0 -> Color.BLACK
            1 -> Color.BLUE
            2 -> Color.RED
            3 -> Color.GRAY
            4 -> Color.YELLOW
            else -> Color.GREEN
        }

        for (i in 0 until CELL_COUNT) {
            for (j in 0 until CELL_COUNT) {
                val rect = cells[i][j]
                canvas.drawText("X", rect.exactCenterX(), rect.exactCenterY(), textPaint)
            }
        }
    }

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_UP -> {
                for (i in 0 until CELL_COUNT) {
                    for (j in 0 until CELL_COUNT) {
                        val rect = cells[i][j]
                        if (rect.contains(event.x.toInt(), event.y.toInt())) {
                            colorNumber += (j + 7)
                            Timber.d("Rect: ${rect.flattenToString()}")
                            invalidate(rect)
                        }
                    }
                }
            }
        }
        return true
    }
}
0

There are 0 best solutions below