Android自定义控件实现九宫格解锁功能

最终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>

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

时间: 2024-09-20 09:36:36

Android自定义控件实现九宫格解锁功能的相关文章

Android 仿小米锁屏实现九宫格解锁功能(无需图片资源)_Android

 最近公司要求做个九宫格解锁,本人用的是小米手机,看着他那个设置锁屏九宫格很好看,就做了该组件,不使用图片资源,纯代码实现. 尊重每个辛苦的博主,在http://blog.csdn.net/mu399/article/details/38734449的基础上进行修改 效果图: 关键代码类: MathUtil.Java /** * @author SoBan * @create 2016/12/5 15:52. */ public class MathUtil { public static do

Android 仿小米锁屏实现九宫格解锁功能(无需图片资源)

最近公司要求做个九宫格解锁,本人用的是小米手机,看着他那个设置锁屏九宫格很好看,就做了该组件,不使用图片资源,纯代码实现. 尊重每个辛苦的博主,在http://blog.csdn.net/mu399/article/details/38734449的基础上进行修改 效果图: 关键代码类: MathUtil.Java /** * @author SoBan * @create 2016/12/5 15:52. */ public class MathUtil { public static dou

云锁新增九宫格解锁功能 安全业界首创

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 九宫格与安全,貌似不风马牛不相及的两个事物被云锁创新的整合到一起,犹如给服务器安全这一低调稳健的行业扔出一枚核弹,立即引起巨大反响. 据椒图科技常务副李科透露,云锁九宫格解锁功能设计灵感源于手机,在保证服务器运维人员系统安全的前提下,云锁大胆创新,将传统敲击键盘输入密码的形式改为九宫格连线的形式,进一步方便了运维人员的服务器登录操作,大大节省

Android手机屏幕敲击解锁功能代码

1.前言 现在市面上有不少Android手机支持敲击屏幕解锁,敲击屏幕解锁是一项很实用的功能,但一来只支持敲击屏幕,二来只能用于解锁或锁屏,再者我们应用层的开发者切不进去,完全无法玩起来.开发者,开发者,我们既然身为开发者何不搞点大新闻,那么这次我来教教各位如何用代码来实现手机的敲击识别,听起来是不是很有趣,有些跃跃欲试呢.事实上在ios上已经有实现这个功能的应用:Knock,一款敲击来解锁Mac电脑的应用,售价4.99美元,约为33人民币.有时候真想去做ios开发,可以开心的为自己的应用定价,

使用Android自定义控件实现滑动解锁九宫格

本文概述: 滑动解锁九宫格的分析: 1.需要自定义控件: 2.需要重写事件onTouchEvent(); 3.需要给九个点设置序号和坐标,这里用Map类就行: 4.需要判断是否到滑到过九点之一,并存储滑到过的点的序号,而且需要一个方法可以返回它们,这里用List类就行: 滑动解锁当前还是比较流行的,今天写了个简单的滑动解锁九宫格的例程,分享出来让初学者看看. 我的是这样的: Demo 首先,自定义一个View /** * 九宫格 */ public class NineGridView exte

太帅了!Android 5.0十二大新功能详解

2014年10月15日,Google公司发布全新的Android 操作系统Android 5.0 Lollipop(棒棒糖).距离Android系统上一次重大更新还不到一年的时间,Android从4.4 KitKat(巧克力棒)升级到了Lollipop(棒棒糖).和每年的惯例一样,Google惯例推出自家品牌Nexus phone和Nexus tablet的新产品.但最大不同是,Android Lollipop的发布成为Android系统有史以来变化最大的一次升级. 12个独特之处,带你快速了解

Android实现九宫格解锁的方法_Android

相信大家都有使用九宫格解锁,比如在设置手机安全项目中,可以使用九宫格解锁,提高安全性,以及在使用支付功能的时候,为了提高安全使用九宫锁,今天就为大家介绍Android实现九宫格的方法,分享给大家供大家参考.具体如下: 运行效果截图如下: 具体代码如下: 布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas

Android实现九宫格解锁的实例代码

当年感觉九宫格解锁很是高大上,一脸懵逼,今天正好要做解锁这一块业务,回头来看九宫格,这特么简单啊 首先理清一下逻辑,我们要做NxN的九宫格 下图是3x3的简单图例 // -(--)-(--)-(--)- // -(--)-(--)-(--)- // -(--)-(--)-(--)- 我们就把九宫格分解成 外圆 .内圆.连线三部分 外圆半径Radius,内圆半径dp(5) 建立一个集合来放置 外圆的圆心( 内圆的圆心也一样) private ArrayList<Point> mListCircl

Html5实现手机九宫格密码解锁功能

HTML5真的是很强大,前端时间看到一个canvas实现九宫格的密码解锁.今天抽出时间模仿了一个,特定分享一下! 效果截图如下: 效果看起来还不错吧! 源码如下: <!DOCTYPE html> <html> <head lang="zh-CN"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"