轻松实现Android自定义九宫格图案解锁
程序员文章站
2024-03-01 20:12:10
android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下:
lockpatternview.java
package com.jackie.l...
android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下:
lockpatternview.java
package com.jackie.lockpattern; import android.content.context; import android.graphics.canvas; import android.graphics.paint; import android.graphics.point; import android.text.textutils; import android.util.attributeset; import android.util.typedvalue; import android.view.motionevent; import android.view.view; import java.util.arraylist; import java.util.list; /** * created by jackie on 2015/12/24. * 图案解锁 */ public class lockpatternview extends view { /** * 圆的画笔 */ private paint mcirclepaint; /** * 线的画笔 */ private paint mlinepaint; /** * 圆心数组 */ private pointview[][] mpointviewarray = new pointview[3][3]; /** * 保存选中点的集合 */ private list<pointview> mselectedpointviewlist; /** * 解锁图案的边长 */ private int mpatternwidth; /** * 图案监听器 */ private onpatternchangelistener monpatternchangelistener; /** * 半径 */ private float mradius; /** * 每个圆圈的下标 */ private int mindex = 1; /** * 第一个点是否选中 */ private boolean misselected; /** * 是否绘制结束 */ private boolean misfinished; /** * 正在滑动并且没有任何点选中 */ private boolean mismovingwithoutcircle = false; private float mcurrentx, mcurrenty; /** * 正常状态的颜色 */ private static final int normal_color = 0xff70dbdb; /** * 选中状态的颜色 */ private static final int selected_color = 0xff979797; public lockpatternview(context context) { this(context, null); } public lockpatternview(context context, attributeset attrs) { super(context, attrs); mcirclepaint = new paint(); mcirclepaint.setantialias(true); mcirclepaint.setdither(true); mcirclepaint.setcolor(normal_color); mcirclepaint.setstyle(paint.style.fill); mlinepaint = new paint(); mlinepaint.setantialias(true); mlinepaint.setdither(true); mlinepaint.setstrokewidth(20); mlinepaint.setcolor(selected_color); mlinepaint.setstyle(paint.style.stroke); mradius = typedvalue.applydimension(typedvalue.complex_unit_dip, 20, getresources().getdisplaymetrics()); mselectedpointviewlist = new arraylist<>(); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //取屏幕长和宽中的较小值作为图案的边长 mpatternwidth = math.min(getmeasuredwidth(), getmeasuredheight()); setmeasureddimension(mpatternwidth, mpatternwidth); } @override protected void ondraw(canvas canvas) { //画圆 drawcircle(canvas); //将选中的圆重新绘制一遍,将选中的点和未选中的点区别开来 for (pointview pointview : mselectedpointviewlist) { mcirclepaint.setcolor(selected_color); canvas.drawcircle(pointview.x, pointview.y, mradius, mcirclepaint); mcirclepaint.setcolor(normal_color); //每重新绘制一个,将画笔的颜色重置,保证不会影响其他圆的绘制 } //点与点画线 if (mselectedpointviewlist.size() > 0) { point pointviewa = mselectedpointviewlist.get(0); //第一个选中的点为a点 for (int i = 0; i < mselectedpointviewlist.size(); i++) { point pointviewb = mselectedpointviewlist.get(i); //其他依次遍历出来的点为b点 drawline(canvas, pointviewa, pointviewb); pointviewa = pointviewb; } //点与鼠标当前位置绘制轨迹 if (mismovingwithoutcircle & !misfinished) { drawline(canvas, pointviewa, new pointview((int)mcurrentx, (int)mcurrenty)); } } super.ondraw(canvas); } /** * 画圆 * @param canvas 画布 */ private void drawcircle(canvas canvas) { //初始化点的位置 for (int i = 0; i < mpointviewarray.length; i++) { for (int j = 0; j < mpointviewarray.length; j++) { //圆心的坐标 int cx = mpatternwidth / 4 * (j + 1); int cy = mpatternwidth / 4 * (i + 1); //将圆心放在一个点数组中 pointview pointview = new pointview(cx, cy); pointview.setindex(mindex); mpointviewarray[i][j] = pointview; canvas.drawcircle(cx, cy, mradius, mcirclepaint); mindex++; } } mindex = 1; } /** * 画线 * @param canvas 画布 * @param pointa 第一个点 * @param pointb 第二个点 */ private void drawline(canvas canvas, point pointa, point pointb) { canvas.drawline(pointa.x, pointa.y, pointb.x, pointb.y, mlinepaint); } @override public boolean ontouchevent(motionevent event) { mcurrentx = event.getx(); mcurrenty = event.gety(); pointview selectedpointview = null; switch(event.getaction()) { case motionevent.action_down: //重新绘制 if (monpatternchangelistener != null) { monpatternchangelistener.onpatternstarted(true); } mselectedpointviewlist.clear(); misfinished = false; selectedpointview = checkselectpoint(); if (selectedpointview != null) { //第一次按下的位置在圆内,被选中 misselected = true; } break; case motionevent.action_move: if (misselected) { selectedpointview = checkselectpoint(); } if (selectedpointview == null) { mismovingwithoutcircle = true; } break; case motionevent.action_up: misfinished = true; misselected = false; break; } //将选中的点收集起来 if (!misfinished && misselected && selectedpointview != null) { if (!mselectedpointviewlist.contains(selectedpointview)) { mselectedpointviewlist.add(selectedpointview); } } if (misfinished) { if (mselectedpointviewlist.size() == 1) { mselectedpointviewlist.clear(); } else if (mselectedpointviewlist.size() < 5 && mselectedpointviewlist.size() > 0) { //绘制错误 if (monpatternchangelistener != null) { monpatternchangelistener.onpatternchange(null); } } else { //绘制成功 string patternpassword = ""; if (monpatternchangelistener != null) { for (pointview pointview : mselectedpointviewlist) { patternpassword += pointview.getindex(); } if (!textutils.isempty(patternpassword)) { monpatternchangelistener.onpatternchange(patternpassword); } } } } invalidate(); return true; } /** * 判断当前按下的位置是否在圆心数组中 * @return 返回选中的点 */ private pointview checkselectpoint() { for (int i = 0; i < mpointviewarray.length; i++) { for (int j = 0; j < mpointviewarray.length; j++) { pointview pointview = mpointviewarray[i][j]; if (iswithincircle(mcurrentx, mcurrenty, pointview.x, pointview.y, mradius)) { return pointview; } } } return null; } /** * 判断点是否在圆内 * @param x 点x轴坐标 * @param y 点y轴坐标 * @param cx 圆心x坐标 * @param cy 圆心y坐标 * @param radius 半径 * @return true表示在圆内,false表示在圆外 */ private boolean iswithincircle(float x, float y, float cx, float cy, float radius) { //如果点和圆心的距离小于半径,则证明点在圆内 if (math.sqrt(math.pow(x - cx, 2) + math.pow(y- cy, 2)) <= radius) { return true; } return false; } /** * 设置图案监听器 */ public void setonpatternchangelistener(onpatternchangelistener onpatternchangelistener) { if (onpatternchangelistener != null) { this.monpatternchangelistener = onpatternchangelistener; } } /** * 图案监听器 */ public interface onpatternchangelistener { /** * 图案改变 * @param patternpassword 图案密码 */ void onpatternchange(string patternpassword); /** * 图案是否重新绘制 * @param isstarted 重新绘制 */ void onpatternstarted(boolean isstarted); } }
pointview.java
package com.jackie.lockpattern; import android.graphics.point; /** * created by jackie on 2015/12/25. * 自定义点对象 */ public class pointview extends point { //用于转化密码的下标 public int index; public pointview(int x, int y) { super(x, y); } public int getindex() { return index; } public void setindex(int index) { this.index = index; } }
mainactivity.java
package com.jackie.lockpattern; import android.app.activity; import android.os.bundle; import android.widget.textview; public class mainactivity extends activity implements lockpatternview.onpatternchangelistener { private textview mlockpatternhint; private lockpatternview mlockpatternview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mlockpatternhint = (textview) findviewbyid(r.id.lock_pattern_hint); mlockpatternview = (lockpatternview) findviewbyid(r.id.lock_pattern_view); mlockpatternview.setonpatternchangelistener(this); } @override public void onpatternchange(string patternpassword) { if (patternpassword == null) { mlockpatternhint.settext("至少5个点"); } else { mlockpatternhint.settext(patternpassword); } } @override public void onpatternstarted(boolean isstarted) { if (isstarted) { mlockpatternhint.settext("请绘制图案"); } } }
效果图如下:
附上源码地址:https://github.com/shineflower/lockpattern.git
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: CSS滤镜参考