You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Android自定义View点击矩阵单元格获取对象并修改颜色的实现

自定义View矩阵单元格点击变色实现方案

首先梳理原有代码的核心错误点:

  • 网格初始化逻辑错误:在onDraw中重复调用initGrid和grid方法,每次重绘都会重新生成整个Cell数组,之前修改的颜色状态会被完全覆盖,无法保留
  • 点击坐标判断错误:onTouchEvent中给contain方法传的是Cell自身的坐标,不是用户点击的坐标,所有判断恒为true,无法匹配真实点击位置
  • Cell状态设计缺失:没有给Cell加选中状态变量,每次show都是固定绘制黑色,修改颜色的逻辑没有和绘制逻辑绑定
  • Canvas滥用:不能在Cell里保存Canvas对象,onDraw传入的Canvas是临时对象,下一次重绘就会失效,需要在Cell的show方法中接收外部传入的Canvas
  • 触摸事件返回值错误:ACTION_DOWN事件默认返回super结果,系统会认为你不消费该事件,后续触摸事件都无法接收,需要主动返回true消费事件

修正后的Cell类

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect

class Cell(var col : Int , var row : Int, x : Int, y: Int, right: Int, bottom: Int){
    var x = x
    var y = y
    var right = right
    var bottom = bottom
    // 新增选中状态标记,默认未选中为红色,选中为绿色
    var isSelected = false

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val rect = Rect(x,y,right,bottom)

    fun show(canvas: Canvas){
        // 根据选中状态动态设置填充色
        paint.color = if(isSelected) Color.GREEN else Color.RED
        paint.style = Paint.Style.FILL
        canvas.drawRect(rect,paint)
        // 绘制白色边框
        paint.color = Color.WHITE
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 4.0f
        canvas.drawRect(rect,paint)
    }

    fun contain(touchX: Int, touchY: Int) : Boolean{
        return touchX in x until right && touchY in y until bottom
    }
}

修正后的Board类

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View

class Board : View {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet): super(context, attrs)

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val boardCol = Color.CYAN
    private val size = 1000
    private lateinit var board : Array<Array<Cell>>
    private val dim = size / 10

    init {
        // 网格仅在初始化时生成一次,避免重复覆盖状态
        initGrid()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 绘制背景
        paint.color = boardCol
        paint.style = Paint.Style.FILL
        canvas.drawRect(0,0,size,size, paint)
        // 绘制所有单元格
        board.forEach { row ->
            row.forEach { cell ->
                cell.show(canvas)
            }
        }
    }

    private fun initGrid() {
        board = Array(10) { i ->
            Array(10) { j ->
                val px = i * dim
                val py = j * dim
                Cell(i, j, px, py, px + dim, py + dim)
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // 获取用户真实点击坐标
                val touchX = event.x.toInt()
                val touchY = event.y.toInt()
                // 遍历匹配点击对应的单元格
                outer@ for(i in board.indices) {
                    for (j in board[i].indices) {
                        if (board[i][j].contain(touchX, touchY)) {
                            // 切换选中状态
                            board[i][j].isSelected = !board[i][j].isSelected
                            // 匹配到后提前跳出循环
                            break@outer
                        }
                    }
                }
                // 触发重绘更新界面
                invalidate()
                // 消费当前触摸事件
                return true
            }
        }
        return super.onTouchEvent(event)
    }
}

内容的提问来源于stack exchange,提问作者francisRH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:24:01