软件编程
位置:首页>> 软件编程>> Android编程>> Android自定义View实现九宫格图形解锁(Kotlin版)

Android自定义View实现九宫格图形解锁(Kotlin版)

作者:一个 狠人  发布时间:2022-04-09 11:10:50 

标签:Android,九宫格,解锁

本文实例为大家分享了Android自定义View实现九宫格图形解锁的具体代码,供大家参考,具体内容如下

效果:

Android自定义View实现九宫格图形解锁(Kotlin版)

代码:


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>

来源:https://blog.csdn.net/WLX10428/article/details/120175305

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com