android自定义View实现手势解锁

文章介绍了如何在Android应用中实现一个基于手势解锁的功能,通过自定义MyGestureLockView和MyCycle类,处理onTouch事件和绘制路径,实现实时更新和验证用户手势输入。
摘要由CSDN通过智能技术生成

有时候为了程序的安全性,我们经常要采取一些安全措施,就像我们常用的支付宝那样,隔一定的时间再回到应用程序时会让用户利用手势去解锁应用程序,最近由于项目需求,也要求做这样一个功能,当用户切出本应用程序15分钟后回来,让用户手势解锁,整个需求的难点就在如何实现这个手势锁,开始一点头绪也没有,没有一点思路去实现这个手势解锁功能,在google了一番后看了一篇非常好的博客后,按照博主的思路的确是可以实现一个十分不错的手势锁View,也参考了下那位大神的代码,下面是我根据他的思路和代码片段实现的一个自定义手势解锁 View,先看效果图.

这是自定义View的初始效果图:

img

以下是绘制手势时的效果图:

img

下面是实现的demo代码:

package com.example.gesturelock; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Timer; 
import java.util.TimerTask; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Path; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 
import com.example.gesturelock.GestureLockView.OnGestureFinishListener; 
public class MyGestureLockView extends View { 
/** 
* 不同状态的画笔 
*/ 
private Paint paintNormal; 
private Paint paintOnTouch; 
private Paint paintInnerCycle; 
private Paint paintLines; 
private Paint paintKeyError; 
private MyCycle[] cycles; 
private Path linePath = new Path(); 
private List<Integer  linedCycles = new ArrayList<Integer (); 
private OnGestureFinishListener onGestureFinishListener; 
private String key; 
private int eventX, eventY; 
private boolean canContinue = true; 
private boolean result; 
private Timer timer; 
/** 
* 不同状态下的色值 
*/ 
private int OUT_CYCLE_NORMAL = Color.rgb(108, 119, 138); // ������Բ��ɫ 
private int OUT_CYCLE_ONTOUCH = Color.rgb(025, 066, 103); // ѡ����Բ��ɫ 
private int INNER_CYCLE_ONTOUCH = Color.rgb(002, 210, 255); // ѡ����Բ��ɫ 
private int LINE_COLOR = Color.argb(127, 002, 210, 255); // ��������ɫ 
private int ERROR_COLOR = Color.argb(127, 255, 000, 000); 
public void setOnGestureFinishListener( 
OnGestureFinishListener onGestureFinishListener) { 
this.onGestureFinishListener = onGestureFinishListener; 
} 
public void setKey(String key) { 
this.key = key; 
} 
public MyGestureLockView(Context context, AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
init(); 
} 
public MyGestureLockView(Context context, AttributeSet attrs) { 
super(context, attrs); 
init(); 
} 
public MyGestureLockView(Context context) { 
super(context); 
init(); 
} 
private void init() { 
paintNormal = new Paint(); 
paintNormal.setAntiAlias(true); 
paintNormal.setStrokeWidth(3); 
paintNormal.setStyle(Paint.Style.STROKE); 
paintOnTouch = new Paint(); 
paintOnTouch.setAntiAlias(true); 
paintOnTouch.setStrokeWidth(3); 
paintOnTouch.setStyle(Paint.Style.STROKE); 
paintInnerCycle = new Paint(); 
paintInnerCycle.setAntiAlias(true); 
paintInnerCycle.setStyle(Paint.Style.FILL); 
paintLines = new Paint(); 
paintLines.setAntiAlias(true); 
paintLines.setStyle(Paint.Style.STROKE); 
paintLines.setStrokeWidth(6); 
paintKeyError = new Paint(); 
paintKeyError.setAntiAlias(true); 
paintKeyError.setStyle(Paint.Style.STROKE); 
paintKeyError.setStrokeWidth(3); 
} 
@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
// TODO Auto-generated method stub 
super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
} 
@Override 
protected void onLayout(boolean changed, int left, int top, int right, 
int bottom) { 
// TODO Auto-generated method stub 
super.onLayout(changed, left, top, right, bottom); 
int perSize = 0; 
if (cycles == null && (perSize = getWidth() / 6)   0) { 
cycles = new MyCycle[9]; 
for (int i = 0; i < 3; i++) { 
for (int j = 0; j < 3; j++) { 
MyCycle cycle = new MyCycle(); 
cycle.setNum(i * 3 + j); 
cycle.setOx(perSize * (j * 2 + 1)); 
cycle.setOy(perSize * (i * 2 + 1)); 
cycle.setR(perSize * 0.5f); 
cycles[i * 3 + j] = cycle; 
} 
} 
} 
} 
/** 
* 绘制所需要绘制的内容 
*/ 
@Override 
protected void onDraw(Canvas canvas) { 
// TODO Auto-generated method stub 
super.onDraw(canvas); 
for (int i = 0; i < cycles.length; i++) { 
if (!canContinue && !result) { 
paintOnTouch.setColor(ERROR_COLOR); 
paintInnerCycle.setColor(ERROR_COLOR); 
paintLines.setColor(ERROR_COLOR); 
} else if (cycles[i].isOnTouch()) { 
paintOnTouch.setColor(OUT_CYCLE_ONTOUCH); 
paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); 
paintLines.setColor(LINE_COLOR); 
} else { 
paintNormal.setColor(OUT_CYCLE_NORMAL); 
paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); 
paintLines.setColor(LINE_COLOR); 
} 
if (cycles[i].isOnTouch()) { 
canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), 
cycles[i].getR(), paintOnTouch); 
drawInnerBuleCycle(cycles[i], canvas); 
} else { 
canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), 
cycles[i].getR(), paintNormal); 
} 
} 
drawLine(canvas); 
} 
/** 
* 绘制大圆里的小圆 
* 
* @param canvas 
*/ 
private void drawInnerBuleCycle(MyCycle cycle, Canvas canvas) { 
canvas.drawCircle(cycle.getOx(), cycle.getOy(), cycle.getR() / 3, 
paintInnerCycle); 
} 
private void drawLine(Canvas canvas) { 
linePath.reset(); 
if (linedCycles.size()   0) { 
for (int i = 0; i < linedCycles.size(); i++) { 
int index = linedCycles.get(i); 
if (i == 0) { 
// 设置为整条路径的起点 
linePath.moveTo(cycles[index].getOx(), cycles[i].getOy()); 
} else { 
linePath.lineTo(cycles[i].getOx(), cycles[i].getOy()); 
} 
} 
linePath.lineTo(eventX, eventY); 
canvas.drawPath(linePath, paintLines); 
} 
} 
/** 
* 根据手择时触摸点的不同,修改对应的状态值 
*/ 
@Override 
public boolean onTouchEvent(MotionEvent event) { 
if (canContinue) { 
switch (event.getAction()) { 
case MotionEvent.ACTION_DOWN: 
case MotionEvent.ACTION_MOVE: 
eventX = (int) event.getX(); 
eventY = (int) event.getY(); 
for (int i = 0; i < cycles.length; i++) { 
if (cycles[i].isPointIn(eventX, eventY)) { 
cycles[i].setOnTouch(true); 
if (!linedCycles.contains(cycles[i].getNum())) { 
linedCycles.add(cycles[i].getNum()); 
} 
} 
} 
break; 
case MotionEvent.ACTION_UP: 
canContinue = false; 
StringBuffer sb = new StringBuffer(); 
for (int i = 0; i < linedCycles.size(); i++) { 
sb.append(linedCycles.get(i)); 
} 
result = key.equals(sb.toString()); 
if (onGestureFinishListener != null) { 
onGestureFinishListener.OnGestureFinish(result); 
} 
timer = new Timer(); 
timer.schedule(new TimerTask() { 
@Override 
public void run() { 
// 回到初始状态 
eventX = eventY = 0; 
for (int i = 0; i < cycles.length; i++) { 
cycles[i].setOnTouch(false); 
} 
linedCycles.clear(); 
linePath.reset(); 
canContinue = true; 
postInvalidate(); 
} 
}, 1000); 
break; 
} 
} 
invalidate(); 
return true; 
} 
} 

自定义圆类:

package com.example.gesturelock; 
public class MyCycle { 
private int ox;     // Բ�ĺ����� 
private int oy;     // Բ�������� 
private float r;     // �뾶���� 
private Integer num;   // ������ֵ 
private boolean onTouch; // false=δѡ�� 
public int getOx() { 
return ox; 
} 
public void setOx(int ox) { 
this.ox = ox; 
} 
public int getOy() { 
return oy; 
} 
public void setOy(int oy) { 
this.oy = oy; 
} 
public float getR() { 
return r; 
} 
public void setR(float r) { 
this.r = r; 
} 
public Integer getNum() { 
return num; 
} 
public void setNum(Integer num) { 
this.num = num; 
} 
public boolean isOnTouch() { 
return onTouch; 
} 
public void setOnTouch(boolean onTouch) { 
this.onTouch = onTouch; 
} 
public boolean isPointIn(int x, int y) { 
double distance = Math.sqrt((x - ox) * (x - ox) + (y - oy) * (y - oy)); 
return distance < r; 
} 
} 

思路:

1.自定义一个 View和MyCircle类,将九个MyCircle类的实例绘制到View中.

2.处理onTouch事件,根据不同的事件修改MyCircle实例的状态,并调用更新invaildate更新View

3.重写onDraw()方法,根据不同的状态去重新绘制整个View

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

更多Android进阶指南 可以扫码 解锁 《Android十大板块文档》

1.Android车载应用开发系统学习指南(附项目实战)

2.Android Framework学习指南,助力成为系统级开发高手

3.2024最新Android中高级面试题汇总+解析,告别零offer

4.企业级Android音视频开发学习路线+项目实战(附源码)

5.Android Jetpack从入门到精通,构建高质量UI界面

6.Flutter技术解析与实战,跨平台首要之选

7.Kotlin从入门到实战,全方面提升架构基础

8.高级Android插件化与组件化(含实战教程和源码)

9.Android 性能优化实战+360°全方面性能调优

10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值