Android自定义控件实现九宫格解锁功能
程序员文章站
2023-12-04 11:24:28
最终android九宫格解锁效果如下
1.进行定义实体point点
public class point {
private float x;...
最终android九宫格解锁效果如下
1.进行定义实体point点
public class point { private float x; private float y; //正常模式 public static final int normal_mode = 1; //按下模式 public static final int pressed_mode = 2; //错误模式 public static final int error_mode = 3; private int state = normal_mode; private string mark; public point(float x, float y, string mark) { this.x = x; this.y = y; this.mark = mark; } public float getx() { return x; } public void setx(float x) { this.x = x; } public float gety() { return y; } public void sety(float y) { this.y = y; } public int getstate() { return state; } public void setstate(int state) { this.state = state; } public string getmark() { return mark; } public void setmark(string mark) { this.mark = mark; } }
2.自定义screenlockview
public class screenlockview extends view { private static final string tag = "screenlockview"; // 错误格子的图片 private bitmap errorbitmap; // 正常格子的图片 private bitmap normalbitmap; // 手指按下时格子的图片 private bitmap pressedbitmap; // 错误时连线的图片 private bitmap lineerrorbitmap; // 手指按住时连线的图片 private bitmap linepressedbitmap; // 偏移量,使九宫格在屏幕* private int offset; // 九宫格的九个格子是否已经初始化 private boolean init; // 格子的半径 private int radius; // 密码 private string password = "123456"; // 九个格子 private point[][] points = new point[3][3]; private int width; private int height; private matrix matrix = new matrix(); private float movex = -1; private float movey = -1; // 是否手指在移动 private boolean ismove; // 是否可以触摸,当用户抬起手指,划出九宫格的密码不正确时为不可触摸 private boolean istouch = true; // 用来存储记录被按下的点 private list<point> pressedpoint = new arraylist<>(); // 屏幕解锁监听器 private onscreenlocklistener listener; public screenlockview(context context) { super(context); init(); } public screenlockview(context context, attributeset attrs) { super(context, attrs); init(); } public screenlockview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(); } private void init() { errorbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.bitmap_error); normalbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.bitmap_normal); pressedbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.bitmap_pressed); lineerrorbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.line_error); linepressedbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.line_pressed); radius = normalbitmap.getwidth() / 2; } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int widthsize = measurespec.getsize(widthmeasurespec); int widthmode = measurespec.getmode(widthmeasurespec); int heightsize = measurespec.getsize(heightmeasurespec); int heightmode = measurespec.getmode(heightmeasurespec); if (widthsize > heightsize) { offset = (widthsize - heightsize) / 2; } else { offset = (heightsize - widthsize) / 2; } setmeasureddimension(widthsize, heightsize); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); if (!init) { width = getwidth(); height = getheight(); initpoint(); init = true; } drawpoint(canvas); if (movex != -1 && movey != -1) { drawline(canvas); } } // 画直线 private void drawline(canvas canvas) { // 将pressedpoint中的所有格子依次遍历,互相连线 for (int i = 0; i < pressedpoint.size() - 1; i++) { // 得到当前格子 point point = pressedpoint.get(i); // 得到下一个格子 point nextpoint = pressedpoint.get(i + 1); // 旋转画布 canvas.rotate(rotatedegrees.getdegrees(point, nextpoint), point.getx(), point.gety()); matrix.reset(); // 根据距离设置拉伸的长度 matrix.setscale(getdistance(point, nextpoint) / linepressedbitmap.getwidth(), 1f); // 进行平移 matrix.posttranslate(point.getx(), point.gety() - linepressedbitmap.getwidth() / 2); if (point.getstate() == point.pressed_mode) { canvas.drawbitmap(linepressedbitmap, matrix, null); } else { canvas.drawbitmap(lineerrorbitmap, matrix, null); } // 把画布旋转回来 canvas.rotate(-rotatedegrees.getdegrees(point, nextpoint), point.getx(), point.gety()); } // 如果是手指在移动的情况 if (ismove) { point lastpoint = pressedpoint.get(pressedpoint.size() - 1); canvas.rotate(rotatedegrees.getdegrees(lastpoint, movex, movey), lastpoint.getx(), lastpoint.gety()); matrix.reset(); log.i(tag, "the distance : " + getdistance(lastpoint, movex, movey) / linepressedbitmap.getwidth()); matrix.setscale(getdistance(lastpoint, movex, movey) / linepressedbitmap.getwidth(), 1f); matrix.posttranslate(lastpoint.getx(), lastpoint.gety() - linepressedbitmap.getwidth() / 2); canvas.drawbitmap(linepressedbitmap, matrix, null); canvas.rotate(-rotatedegrees.getdegrees(lastpoint, movex, movey), lastpoint.getx(), lastpoint.gety()); } } // 根据point和坐标点计算出之间的距离 private float getdistance(point point, float movex, float movey) { point b = new point(movex,movey,null); return getdistance(point,b); } // 根据两个point计算出之间的距离 private float getdistance(point point, point nextpoint) { return (float) math.sqrt(math.pow(nextpoint.getx() - point.getx(), 2f) + math.pow(nextpoint.gety() - point.gety(), 2f)); } private void drawpoint(canvas canvas) { for (int i = 0; i < points.length; i++) { for (int j = 0; j < points[i].length; j++) { int state = points[i][j].getstate(); if (state == point.normal_mode) { canvas.drawbitmap(normalbitmap, points[i][j].getx() - radius, points[i][j].gety() - radius, null); } else if (state == point.pressed_mode) { canvas.drawbitmap(pressedbitmap, points[i][j].getx() - radius, points[i][j].gety() - radius, null); } else { canvas.drawbitmap(errorbitmap, points[i][j].getx() - radius, points[i][j].gety() - radius, null); } } } } //初始化九宫格的点 private void initpoint() { points[0][0] = new point(width / 4, offset + width / 4, "0"); points[0][1] = new point(width / 2, offset + width / 4, "1"); points[0][2] = new point(width * 3 / 4, offset + width / 4, "2"); points[1][0] = new point(width / 4, offset + width / 2, "3"); points[1][1] = new point(width / 2, offset + width / 2, "4"); points[1][2] = new point(width * 3 / 4, offset + width / 2, "5"); points[2][0] = new point(width / 4, offset + width * 3 / 4, "6"); points[2][1] = new point(width / 2, offset + width * 3 / 4, "7"); points[2][2] = new point(width * 3 / 4, offset + width * 3 / 4, "8"); } @override public boolean ontouchevent(motionevent event) { if (istouch) { float x = event.getx(); float y = event.gety(); point point; switch (event.getaction()) { case motionevent.action_down: // 判断用户触摸的点是否在九宫格的任意一个格子之内 point = ispoint(x, y); if (point != null) { point.setstate(point.pressed_mode); // 切换为按下模式 pressedpoint.add(point); } break; case motionevent.action_move: if (pressedpoint.size() > 0) { point = ispoint(x, y); if (point != null) { if (!crosspoint(point)) { point.setstate(point.pressed_mode); pressedpoint.add(point); } } movex = x; movey = y; ismove = true; } break; case motionevent.action_up: ismove = false; string temppwd = ""; for (point p : pressedpoint) { temppwd += p.getmark(); } if (listener != null) { listener.getstringpassword(temppwd); } if (temppwd.equals(password)) { if (listener != null) { listener.ispassword(true); this.postdelayed(runnable, 1000); } } else { for (point p : pressedpoint) { p.setstate(point.error_mode); } istouch = false; this.postdelayed(runnable, 1000); if (listener != null) { listener.ispassword(false); } } break; } invalidate(); } return true; } private boolean crosspoint(point point) { if (pressedpoint.contains(point)) { return true; } return false; } public interface onscreenlocklistener { public void getstringpassword(string password); public void ispassword(boolean flag); } public void setonscreenlocklistener(onscreenlocklistener listener) { this.listener = listener; } private point ispoint(float x, float y) { point point; for(int i = 0; i<points.length;i++){ for (int j = 0; j < points[i].length; j++) { point = points[i][j]; if (iscontain(point, x, y)) { return point; } } } return null; } private boolean iscontain(point point, float x, float y) { return math.sqrt(math.pow(x - point.getx(), 2f) + math.pow(y - point.gety(), 2f)) <= radius; } private runnable runnable = new runnable() { @override public void run() { istouch = true; reset(); invalidate(); } }; // 重置格子 private void reset(){ for (int i = 0; i < points.length; i++) { for (int j = 0; j < points[i].length; j++) { points[i][j].setstate(point.normal_mode); } } pressedpoint.clear(); } }
3.rotatedegress类
public class rotatedegrees { public static float getdegrees(point a, point b){ float degrees = 0 ; float ax = a.getx(); float ay = a.gety(); float bx = b.getx(); float by = b.gety(); if(ax == bx){ if(ay<by){ degrees = 90; }else{ degrees = 270; } }else if(by == ay){ if(ax<bx){ degrees = 0 ; }else{ degrees = 180; } }else{ if(ax>bx){ if(ay>by){ degrees = 180 + (float)(math.atan2(ay-by,ax-bx)*180/math.pi); }else{ degrees = 180 - (float)(math.atan2(by -ay,ax - bx)*180/math.pi); } }else{ if(ay>by){ degrees = 360 -(float)(math.atan2(ay - by,bx-ax)*180/math.pi); }else{ degrees = (float)(math.atan2(by - ay,bx - ax)*180/math.pi); } } } return degrees; } public static float getdegrees(point a, float bx,float by){ point b = new point(bx,by,null); return getdegrees(a,b); } }
用到的图片资源
4.mainactivity中使用
public class mainactivity extends appcompatactivity { private screenlockview screenlockview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); screenlockview = (screenlockview) findviewbyid(r.id.slv); screenlockview.setonscreenlocklistener(new screenlockview.onscreenlocklistener() { @override public void getstringpassword(string password) { } @override public void ispassword(boolean flag) { string content; if (flag) { content = "密码正确"; } else { content = "密码错误"; } toast.maketext(mainactivity.this, content, toast.length_short).show(); } }); } }
5.布局文件
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" tools:context="com.example.admin.ninegridunlock.mainactivity"> <com.example.admin.ninegridunlock.screenlockview android:id="@+id/slv" android:layout_width="match_parent" android:layout_height="match_parent" /> </relativelayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: android内存优化之图片优化
推荐阅读