Android 從 0 開始學(xué)習(xí)自定義 View(十一) 自定義九宮格

效果圖

實(shí)現(xiàn)分析

  1. 畫 9 個(gè)圓
  2. 根據(jù)手指觸摸的坐標(biāo)更改圓的顏色
  3. 畫線
  4. 處理手指抬起的狀態(tài)

后面的文章大部分應(yīng)該都會(huì)使用 Kotlin ,隨著 JetPack 和 Compose 的廣泛使用,Kotlin 慢慢成為了趨勢(shì)。如果對(duì) Kotlin 還不了解的推薦一下郭神的 《第一行代碼》Kotlin 版,比較容易上手的 Koltin 入門書籍。

1、畫 9 個(gè)圓

private fun initDot() {
    //初始化9宮格
    //記錄點(diǎn)的狀態(tài),回掉密碼

    //九宮格總寬度
    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
    //內(nèi)圓大小
    inDotWidth = outDotWidth / 6

    //點(diǎn)的位置
    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)
}

圖畫得不是很標(biāo)準(zhǔn),放一張圖方便理解

  1. 考慮到橫豎屏的問(wèn)題,所以會(huì)設(shè)置兩個(gè)方向的偏移量。如果是豎屏對(duì)應(yīng) y 軸偏移量為 0,如果是橫屏對(duì)應(yīng) x 軸偏移量為0
  2. 九宮格在屏幕的中間,所以對(duì)應(yīng)的豎屏偏移量為 ( height - width ) / 2,橫屏為( width - height ) / 2
  3. 一個(gè)圓占屏幕的 1/3,所以圓的直徑為 width / 3 ,半徑為 width / 6
  4. 得到上面的數(shù)據(jù),依次就可以算出 9 宮格每個(gè)中心點(diǎn)的坐標(biāo),最后將大圓和小圓繪制出來(lái)

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. 首先確定手指觸摸的范圍是否在圓內(nèi),如果不在圓內(nèi)則不處理,如果在圓內(nèi)就修改當(dāng)前點(diǎn)的狀態(tài)
  2. 當(dāng)手指在屏幕上移動(dòng)時(shí),判斷移動(dòng)的位置是否包含了點(diǎn),如果沒(méi)有包含則將點(diǎn)添加并修改狀態(tài),如果有則不處理。

3、畫線

private fun drawLine(start: Point, end: Point, canvas: Canvas, paint: Paint) {
    //拿到2點(diǎn)的坐標(biāo)和坐標(biāo)差
    val startX = start.centerX
    val startY = start.centerY
    val endX = end.centerX
    val endY = end.centerY
    val dx = endX - startX
    val dy = endY - startY
    //計(jì)算2點(diǎn)的位置
    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)

}

如果從點(diǎn)中間會(huì)稍微影響九宮格的美觀,所以要減去多余的長(zhǎng)度。貼一張圖,方便理解計(jì)算規(guī)則

4、處理手指抬起

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

這里處理比較簡(jiǎn)單:當(dāng)只存在 1 個(gè)點(diǎn)時(shí)清空狀態(tài);小于 4 個(gè)點(diǎn)時(shí)顯示錯(cuò)誤;其他情況就顯示正確

自定義九宮格就介紹到這里了,如果有什么寫得不對(duì)的,可以在下方評(píng)論留言,我會(huì)第一時(shí)間改正。

Github 源碼鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容