Android自定義View實現九宮格圖形解鎖(Kotlin版)
更新時間:2021年09月10日 10:33:56 作者:一個 狠人
這篇文章主要為大家詳細介紹了Android自定義View實現九宮格圖形解鎖,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了Android自定義View實現九宮格圖形解鎖的具體代碼,供大家參考,具體內容如下
效果:

代碼:
package com.example.kotlin_test
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
/**
* Created by wanglx on 2021/9/8.
*/
class MyLock : View {
private var isInit=false
private var mPoints:Array<Array<Point?>> = Array(3){Array<Point?>(3){null} }
private var mSelectPoints=ArrayList<Point>()
private var isTouch=false
private var code= listOf(0,1,2,5,8)
//畫筆
private lateinit var mNormalPaint:Paint
private lateinit var mPressedPaint:Paint
private lateinit var mErrorPaint: Paint
private lateinit var mLinePaint: Paint
//顏色
private val mNormalColor=Color.BLACK
private val mPressedColor=Color.GREEN
private val mErrorColor=Color.RED
private val mLineColor=Color.BLACK
//外圓半徑
private var mDotRadius=0
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defaultStyle: Int):super(context,attrs,defaultStyle)
override fun onDraw(canvas: Canvas?) {
//初始化
if (!isInit) {
initDot()
initPaint()
isInit=true
}
//繪制
drawShow(canvas)
}
private fun drawShow(canvas: Canvas?) {
for (i in 0..2) {
for (j in 0..2) {
var point = mPoints[i][j]
when(point!!.status){
PointStatus.NORMAL->{
//先畫外圓,再畫內圓
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat(),mNormalPaint)
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat()/6,mNormalPaint)
}
PointStatus.PRESSED->{
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat(),mPressedPaint)
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat()/6,mPressedPaint)
}
PointStatus.ERROR->{
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat(),mErrorPaint)
canvas!!.drawCircle(point.centerX,point.centerY,
mDotRadius.toFloat()/6,mErrorPaint)
}
}
}
}
//畫連線
drawLine(canvas)
}
private fun drawLine(canvas: Canvas?) {
if (mSelectPoints.size > 0) {
var mLastPoint = mSelectPoints[0]
//兩點連線
if (mSelectPoints.size > 1) {
for (i in 1..mSelectPoints.size-1) {
var point = mSelectPoints[i]
realDrawLine(mLastPoint, point, canvas, mLinePaint)
mLastPoint=point
}
}
//手指和某個點的連線
var isInner=checkInRound(mLastPoint.centerX,mLastPoint.centerY,movingX,movingY,mDotRadius/6)
if (!isInner&&isTouch) {
realDrawLine(mLastPoint,Point(movingX,movingY,-1),canvas,mLinePaint)
}
}
}
private fun realDrawLine(
mLastPoint: Point,
point: Point,
canvas: Canvas?,
mLinePaint: Paint
) {
//不是從圓心坐標開始畫,而是距離圓心有一定的距離
var dx=point.centerX-mLastPoint.centerX
var dy=point.centerY-mLastPoint.centerY
var pointDistance = Math.sqrt((dx * dx + dy * dy).toDouble())
var offsetX = (dx / pointDistance) * (mDotRadius / 6)
var offsetY=(dy/pointDistance)*(mDotRadius/6)
canvas!!.drawLine((mLastPoint.centerX+offsetX).toFloat(),
(mLastPoint.centerY+offsetY).toFloat(),
(point.centerX-offsetX).toFloat(), (point.centerY-offsetY).toFloat(),mLinePaint)
}
private var movingX=0f
private var movingY=0f
override fun onTouchEvent(event: MotionEvent?): Boolean {
movingX=event!!.x
movingY=event.y
when (event.action) {
MotionEvent.ACTION_DOWN->{
for (i in 0..mSelectPoints.size - 1) {
mSelectPoints[i].setStatusNormal()
}
mSelectPoints.clear()
invalidate()
//先判斷是不是在圓內
var dd=point
if (dd != null) {
dd.setStatusPressed()
mSelectPoints.add(dd)
isTouch=true
}
}
MotionEvent.ACTION_MOVE->{
//先判斷是不是在圓內
var dd=point
if (dd != null) {
dd.setStatusPressed()
if (!mSelectPoints.contains(dd)) {
mSelectPoints.add(dd)
}
}
}
MotionEvent.ACTION_UP->{
isTouch=false
if (mSelectPoints.size == code.size) {
for (i in 0..mSelectPoints.size - 1) {
if (mSelectPoints[i].index != code[i]) {
for (i in 0..mSelectPoints.size - 1) {
//密碼不對,設置為錯誤狀態(tài)
mSelectPoints[i].setStatusError()
}
break
}
}
} else {
for (i in 0..mSelectPoints.size - 1) {
mSelectPoints[i].setStatusError()
}
}
}
}
invalidate()
return true
}
//擴展屬性,遍歷九個圓,看手指的按在哪個圓里面
val point:Point?
get() {
for (i in 0..2) {
for (j in 0..2) {
var point = mPoints[i][j]
if (checkInRound(point!!.centerX, point.centerY, movingX, movingY, mDotRadius)) {
return point
}
}
}
return null
}
//判斷是不是在圓內
private fun checkInRound(
centerX: Float,
centerY: Float,
movingX: Float,
movingY: Float,
mDotRadius: Int
): Boolean {
var isIn=Math.sqrt(((centerX-movingX)*(centerX-movingX)+(centerY-movingY)*(centerY-movingY)).toDouble())<mDotRadius
return isIn
}
private fun initPaint() {
//正常畫筆
mNormalPaint = Paint()
mNormalPaint!!.color=mNormalColor
mNormalPaint.style=Paint.Style.STROKE
mNormalPaint.isAntiAlias=true
mNormalPaint.strokeWidth=mDotRadius.toFloat()/12
//按下畫筆
mPressedPaint = Paint()
mPressedPaint!!.color=mPressedColor
mPressedPaint.style=Paint.Style.STROKE
mPressedPaint.isAntiAlias=true
mPressedPaint.strokeWidth=mDotRadius.toFloat()/9
//錯誤畫筆
mErrorPaint = Paint()
mErrorPaint!!.color=mErrorColor
mErrorPaint.style=Paint.Style.STROKE
mErrorPaint.isAntiAlias=true
mErrorPaint.strokeWidth=mDotRadius.toFloat()/12
//連線畫筆
mLinePaint = Paint()
mLinePaint!!.color=mLineColor
mLinePaint.style=Paint.Style.STROKE
mLinePaint.isAntiAlias=true
mLinePaint.strokeWidth=mDotRadius.toFloat()/12
}
private fun initDot() {
var width=this.width
var height=this.height
var offsetX=0f//九個宮格為正方形,距離布局左邊的距離
var offsetY=0f//九宮格為正方形,距離布局頂部的距離
//兼容橫豎屏
if (width > height) {
offsetX = (width - height).toFloat() / 2
width = height
} else {
offsetY = (height - width).toFloat() / 2
}
//每個方格的大小
var squareWidth=width/3
mDotRadius=squareWidth/4
//九個宮格,存于數組Point[3][3]
mPoints[0][0] = Point(squareWidth/2+offsetX,squareWidth/2+offsetY,0)
mPoints[0][1] = Point(squareWidth*3/2+offsetX,squareWidth/2+offsetY,1)
mPoints[0][2] = Point(squareWidth*5/2+offsetX,squareWidth/2+offsetY,2)
mPoints[1][0] = Point(squareWidth/2+offsetX,squareWidth*3/2+offsetY,3)
mPoints[1][1] = Point(squareWidth*3/2+offsetX,squareWidth*3/2+offsetY,4)
mPoints[1][2] = Point(squareWidth*5/2+offsetX,squareWidth*3/2+offsetY,5)
mPoints[2][0] = Point(squareWidth/2+offsetX,squareWidth*5/2+offsetY,6)
mPoints[2][1] = Point(squareWidth*3/2+offsetX,squareWidth*5/2+offsetY,7)
mPoints[2][2] = Point(squareWidth*5/2+offsetX,squareWidth*5/2+offsetY,8)
}
//圓的狀態(tài)
enum class PointStatus{
NORMAL,PRESSED,ERROR
}
class Point(var centerX: Float, var centerY: Float, var index: Int){
//默認狀態(tài)
var status = PointStatus.NORMAL
fun setStatusNormal() {
status=PointStatus.NORMAL
}
fun setStatusPressed() {
status=PointStatus.PRESSED
}
fun setStatusError() {
status=PointStatus.ERROR
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.kotlin_test.MyLock
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android程序開發(fā)通過HttpURLConnection上傳文件到服務器
這篇文章主要介紹了Android程序開發(fā)通過HttpURLConnection上傳文件到服務器的相關資料,需要的朋友可以參考下2016-01-01
Android 中使用 ViewPager實現屏幕頁面切換和頁面輪播效果
ViewPager是谷歌官方給我們提供的一個兼容低版本安卓設備的軟件包,里面包囊了只有在安卓3.0以上可以使用的api。下面我們就展示下ViewPager可以實現的兩種簡單效果,感興趣的朋友一起看看吧2016-12-12
Android中Activity常用功能設置小結(包括全屏、橫豎屏等)
這篇文章主要介紹了Android中Activity常用功能設置小結(包括全屏、橫豎屏等),以簡單實例形式分析了Android實現全屏、豎屏及一直顯示等的技巧與注意事項,需要的朋友可以參考下2015-10-10

