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
相关产品推荐
相关产品推荐

