Android 从 0 开始学习自定义 View(十一) 自定义九宫格

效果图

实现分析

  1. 画 9 个圆
  2. 根据手指触摸的坐标更改圆的颜色
  3. 画线
  4. 处理手指抬起的状态

后面的文章大部分应该都会使用 Kotlin ,随着 JetPack 和 Compose 的广泛使用,Kotlin 慢慢成为了趋势。如果对 Kotlin 还不了解的推荐一下郭神的 《第一行代码》Kotlin 版,比较容易上手的 Koltin 入门书籍。

1、画 9 个圆

private fun initDot() {
    //初始化9宫格
    //记录点的状态,回掉密码

    //九宫格总宽度
    var width = this.width
    //九宫格总高度
    var height = this.height

    var offSetY = 0
    var offSetX = 0
    //兼容横竖屏
    if (height > width) {
        //Y轴偏移量
        offSetY = (height - width) / 2
        height = width
    } else {
        //X轴偏移量
        offSetX = (width - height) / 2
        width = height
    }

    //单元格宽度
    var pointWidth = width / 3

    //外圆大小
    outDotWidth = width / 12f
    //内圆大小
    inDotWidth = outDotWidth / 6

    //点的位置
    mPoints[0][0] = Point(offSetX + pointWidth / 2, offSetY + pointWidth / 2, 0)
    mPoints[0][1] = Point(offSetX + pointWidth * 3 / 2, offSetY + pointWidth / 2, 1)
    mPoints[0][2] = Point(offSetX + pointWidth * 5 / 2, offSetY + pointWidth / 2, 2)
    mPoints[1][0] = Point(offSetX + pointWidth / 2, offSetY + pointWidth * 3 / 2, 3)
    mPoints[1][1] = Point(offSetX + pointWidth * 3 / 2, offSetY + pointWidth * 3 / 2, 4)
    mPoints[1][2] = Point(offSetX + pointWidth * 5 / 2, offSetY + pointWidth * 3 / 2, 5)
    mPoints[2][0] = Point(offSetX + pointWidth / 2, offSetY + pointWidth * 5 / 2, 6)
    mPoints[2][1] = Point(offSetX + pointWidth * 3 / 2, offSetY + pointWidth * 5 / 2, 7)
    mPoints[2][2] = Point(offSetX + pointWidth * 5 / 2, offSetY + pointWidth * 5 / 2, 8)
}

图画得不是很标准,放一张图方便理解

  1. 考虑到横竖屏的问题,所以会设置两个方向的偏移量。如果是竖屏对应 y 轴偏移量为 0,如果是横屏对应 x 轴偏移量为0
  2. 九宫格在屏幕的中间,所以对应的竖屏偏移量为 ( height - width ) / 2,横屏为( width - height ) / 2
  3. 一个圆占屏幕的 1/3,所以圆的直径为 width / 3 ,半径为 width / 6
  4. 得到上面的数据,依次就可以算出 9 宫格每个中心点的坐标,最后将大圆和小圆绘制出来

2、手指触摸更改圆的颜色

override fun onTouchEvent(event: MotionEvent): Boolean {
    mMoveX = event.x
    mMoveY = event.y
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            val point = point
            if (point != null) {
                isTouchPoint = true
                selectPoint.add(point)
                point.setStatusPress()
            }
        }
        MotionEvent.ACTION_MOVE -> {
            if (isTouchPoint) {
                val point = point
                if (point != null) {
                    if (!selectPoint.contains(point)) {
                        selectPoint.add(point)
                    }
                    point.setStatusPress()
                }
            }
        }
    }
    invalidate()
    return true
}
  1. 首先确定手指触摸的范围是否在圆内,如果不在圆内则不处理,如果在圆内就修改当前点的状态
  2. 当手指在屏幕上移动时,判断移动的位置是否包含了点,如果没有包含则将点添加并修改状态,如果有则不处理。

3、画线

private fun drawLine(start: Point, end: Point, canvas: Canvas, paint: Paint) {
    //拿到2点的坐标和坐标差
    val startX = start.centerX
    val startY = start.centerY
    val endX = end.centerX
    val endY = end.centerY
    val dx = endX - startX
    val dy = endY - startY
    //计算2点的位置
    val d = (sqrt((dx * dx + dy * dy).toDouble())).toFloat()

    val rx = dx / d * inDotWidth
    val ry = dy / d * inDotWidth

    canvas.drawLine(startX + rx, startY + ry, endX - rx, endY - ry, paint)

}

如果从点中间会稍微影响九宫格的美观,所以要减去多余的长度。贴一张图,方便理解计算规则

4、处理手指抬起

MotionEvent.ACTION_UP -> {
    isTouchPoint = false
    when {
        selectPoint.size == 1 -> {
             clearSelectPoints()
        }
        
        selectPoint.size <= 4 -> {
            showSelectError()
        }
      
        else -> {
            showSelectRight()
        }
    }
}

这里处理比较简单:当只存在 1 个点时清空状态;小于 4 个点时显示错误;其他情况就显示正确

自定义九宫格就介绍到这里了,如果有什么写得不对的,可以在下方评论留言,我会第一时间改正。

Github 源码链接

你可能感兴趣的:(Android 从 0 开始学习自定义 View(十一) 自定义九宫格)