欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-16 21:37:50
本文实例为大家分享了android自定义view实现九宫格图形解锁的具体代码,供大家参考,具体内容如下效果:代码:package com.example.kotlin_test import andr...

本文实例为大家分享了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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。