android自定義View實(shí)現(xiàn)手勢解鎖
有時候?yàn)榱顺绦虻陌踩?我們經(jīng)常要采取一些安全措施,就像我們常用的支付寶那樣,隔一定的時間再回到應(yīng)用程序時會讓用戶利用手勢去解鎖應(yīng)用程序,最近由于項(xiàng)目需求,也要求做這樣一個功能,當(dāng)用戶切出本應(yīng)用程序15分鐘后回來,讓用戶手勢解鎖,整個需求的難點(diǎn)就在如何實(shí)現(xiàn)這個手勢鎖,開始一點(diǎn)頭緒也沒有,沒有一點(diǎn)思路去實(shí)現(xiàn)這個手勢解鎖功能,在google了一番后看了一篇非常好的博客后,按照博主的思路的確是可以實(shí)現(xiàn)一個十分不錯的手勢鎖View,也參考了下那位大神的代碼,下面是我根據(jù)他的思路和代碼片段實(shí)現(xiàn)的一個自定義手勢解鎖 View,先看效果圖.
這是自定義View的初始效果圖:

以下是繪制手勢時的效果圖:

下面是實(shí)現(xiàn)的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 {
/**
* 不同狀態(tài)的畫筆
*/
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;
/**
* 不同狀態(tài)下的色值
*/
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;
}
}
}
}
/**
* 繪制所需要繪制的內(nèi)容
*/
@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) {
// 設(shè)置為整條路徑的起點(diǎn)
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);
}
}
/**
* 根據(jù)手擇時觸摸點(diǎn)的不同,修改對應(yīng)的狀態(tài)值
*/
@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() {
// 回到初始狀態(tài)
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類的實(shí)例繪制到View中.
2.處理onTouch事件,根據(jù)不同的事件修改MyCircle實(shí)例的狀態(tài),并調(diào)用更新invaildate更新View
3.重寫onDraw()方法,根據(jù)不同的狀態(tài)去重新繪制整個View
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 自定義精美界面包含選項(xiàng)菜單 上下文菜單及監(jiān)聽詳解流程
這篇文章主要介紹了一個Android實(shí)例小項(xiàng)目,它包含了選項(xiàng)菜單、上下文菜單及其對應(yīng)的監(jiān)聽事件,它很小,但這部分功能在Android開發(fā)中很常見,需要的朋友來看看吧2021-11-11
Android開發(fā)實(shí)現(xiàn)的圓角按鈕、文字陰影按鈕效果示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)的圓角按鈕、文字陰影按鈕效果,涉及Android界面布局與屬性設(shè)置相關(guān)操作技巧,需要的朋友可以參考下2019-04-04
Android LaunchMode四種啟動模式詳細(xì)介紹
這篇文章主要介紹了Android LaunchMode四種啟動模式詳細(xì)介紹的相關(guān)資料,這里對launchmode的使用方法進(jìn)行了詳解及啟動模式的比較,需要的朋友可以參考下2016-12-12
Android實(shí)戰(zhàn)教程第五篇之一鍵鎖屏應(yīng)用
這篇文章主要為大家詳細(xì)介紹了Android實(shí)戰(zhàn)教程第五篇之一鍵鎖屏應(yīng)用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
Android 截取手機(jī)屏幕兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android 截取手機(jī)屏幕兩種實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android UI設(shè)計(jì)與開發(fā)之PopupWindow仿騰訊新聞底部彈出菜單
這篇文章主要為大家詳細(xì)介紹了Android UI設(shè)計(jì)與開發(fā)之PopupWindow仿騰訊新聞底部彈出菜單,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
Android HorizontalScrollView內(nèi)子控件橫向拖拽實(shí)例代碼
本文主要介紹Android HorizontalScrollView的使用,這里給大家一個實(shí)例來展示HorizontalScrollView內(nèi)子控件橫向拖拽的效果實(shí)現(xiàn),有需要的小伙伴可以參考下2016-07-07
OpenGL Shader實(shí)例分析(8)彩色光圈效果
這篇文章主要為大家詳細(xì)介紹了OpenGL Shader實(shí)例分析第8篇,彩色光圈效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-02-02
viewpager實(shí)現(xiàn)自動循環(huán)輪播圖
這篇文章主要為大家詳細(xì)介紹了viewpager實(shí)現(xiàn)自動循環(huán)輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-01-01

