Android自定义View实现九宫格图形解锁(Kotlin版)
作者:一个 狠人 时间:2022-04-09 11:10:50
本文实例为大家分享了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>
来源:https://blog.csdn.net/WLX10428/article/details/120175305
标签:Android,九宫格,解锁
0
投稿
猜你喜欢
教你使用idea搭建ssm详细教程(Spring+Spring Mvc+Mybatis)
2021-09-23 12:37:42
Spring Boot 中application.yml与bootstrap.yml的区别
2023-07-09 12:30:56
c#中WinForm用OpencvSharp实现ROI区域提取的示例
2023-03-22 13:54:10
SpringBoot Scheduling定时任务的示例代码
2023-08-12 17:55:05
Mybatis-plus多租户项目实战进阶指南
2023-10-10 18:14:43
论Java Web应用中调优线程池的重要性
2023-06-13 04:56:27
SpringBoot集成Spring security JWT实现接口权限认证
2023-02-02 07:31:08
Java类加载器ClassLoader用法解析
2023-05-05 21:46:38
OPENCV+JAVA实现人脸识别
2022-03-15 18:31:39
android开机自启动app示例分享
2023-02-20 18:04:29
详细分析android的MessageQueue.IdleHandler
2023-06-23 19:12:10
一文详解Android无需权限调用系统相机拍照
2022-06-22 03:08:26
spring boot学习笔记之操作ActiveMQ指南
2023-09-12 20:11:52
java之assert关键字用法案例详解
2022-07-10 23:01:32
Flutter Recovering Stream Errors小技巧
2023-09-02 05:02:17
C# WinForm自动更新程序之文件上传操作详解
2022-09-11 21:42:11
MaterialApp Flutter 应用全局配置与主题管理详解
2023-05-03 18:50:48
MyBatis-Plus自动填充功能失效导致的原因及解决
2023-05-11 13:16:08
MyBatis入门实例教程之创建一个简单的程序
2022-04-26 14:38:14
android编程之xml文件读取和写入方法
2022-08-23 05:47:48