Android Kotlin游戏开发:如何让Dot视图匹配圆点实际尺寸?
解决Dot View全屏导致点击错误的问题
核心问题在于:你之前让Dot作为全屏View,在Canvas上绘制小圆点,导致任何屏幕点击都会触发最新添加的Dot的触摸事件;而修改onMeasure后,又错误地使用屏幕绝对坐标绘制圆点,导致圆点被限制在小View内部,无法正常显示位置。
正确的解决思路
- 让
Dot的View尺寸严格匹配圆点大小(直径=60,对应半径30) - 通过布局参数(LayoutParams)控制
Dot在父布局中的位置,而非在Canvas中使用绝对坐标 - 圆点绘制在
DotView的中心,这样View的位置就是圆点的实际位置,触摸范围精准对应圆点
修改后的代码实现
1. 重构Dot.kt
class Dot(context: Context, attrs: AttributeSet?, private var dotColor: Int) : View(context, attrs) { private var isMatching: Boolean = false private var dotIsPressed: Boolean = false private var isDestroyed: Boolean = false private lateinit var mHandler: Handler private lateinit var runnable: Runnable // 用布局参数控制位置 private val layoutParams = ConstraintLayout.LayoutParams( ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT ) init { this.isPressed = false this.isDestroyed = false mHandler = Handler() runnable = object : Runnable { override fun run() { moveDown() invalidate() if (!isDestroyed) { mHandler.postDelayed(this, 20) } } } // 初始化位置:随机水平位置,顶部开始 val random = Random() val screenWidth = context.resources.displayMetrics.widthPixels // 限制水平位置,避免圆点超出屏幕 layoutParams.leftMargin = random.nextInt(screenWidth - 60) layoutParams.topMargin = 0 this.layoutParams = layoutParams startFalling() } fun getDotColor() = dotColor fun isMatching() = isMatching fun setMatching(matching: Boolean) { this.isMatching = matching } fun dotIsPressed() = dotIsPressed override fun setPressed(pressed: Boolean) { this.dotIsPressed = pressed } fun isDestroyed() = isDestroyed fun setDestroyed(destroyed: Boolean) { this.isDestroyed = destroyed if (destroyed) { mHandler.removeCallbacks(runnable) } } fun moveDown() { // 更新topMargin实现下落 layoutParams.topMargin += 10 this.layoutParams = layoutParams } fun checkCollision(line: Line) { // 这里可以根据layoutParams.topMargin和line的位置判断碰撞 } fun startFalling() { mHandler.post(runnable) } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { // 设置View尺寸为圆点直径(60 = 30*2) setMeasuredDimension(60, 60) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) if (!isDestroyed) { val paint = Paint().apply { color = dotColor } // 在View中心绘制圆点 canvas?.drawCircle(width/2f, height/2f, 30f, paint) } } }
2. 修改MainActivity.kt中的createAndAddDot方法
fun createAndAddDot(color: Int) { Log.d("Dot", "createAndAddDot called") val dot = Dot(this, null, color) val layout = findViewById<ConstraintLayout>(R.id.layout) layout.addView(dot) dots.add(dot) dot.setOnTouchListener { view, event -> if (event.action == MotionEvent.ACTION_DOWN) { val dotToRemove = dots.find { it == view } dotToRemove?.let { it.setDestroyed(true) layout.removeView(it) dots.remove(it) updateScore(1) view.performClick() } } true } }
同时修改创建Dot的调用处:
// 原来的代码 createAndAddDot(0, 0, dotColor) // 修改为 createAndAddDot(dotColor)
关键修改点说明
- View尺寸控制:通过
onMeasure固定View为60x60,完全匹配圆点大小,触摸事件只会在这个范围内触发 - 位置控制:用
ConstraintLayout.LayoutParams的leftMargin和topMargin控制Dot在屏幕中的位置,替代原来的绝对坐标xPos、yPos - 绘制逻辑:在View中心绘制圆点,确保圆点始终显示在View范围内,View的位置就是圆点的实际位置
- 内存优化:销毁Dot时移除Handler的回调,避免内存泄漏
内容的提问来源于stack exchange,提问作者Spencer S.
相关产品推荐
相关产品推荐

