Android自定义View实现九宫格图形解锁(Kotlin版)
本文实例为大家分享了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) { //密码不对,设置为错误状态 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) } //圆的状态 enum class PointStatus{ NORMAL,PRESSED,ERROR } class Point(var centerX: Float, var centerY: Float, var index: Int){ //默认状态 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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持海外IDC网。