本文实例为大家分享了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
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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。