android自定义手势解锁View

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

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

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

下面是实现的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

时间: 2024-08-10 23:12:24

android自定义手势解锁View的相关文章

Android自定义View4——统计图View

1.介绍 周末在逛慕课网的时候,看到了一张学习计划报告图,详细记录了自己一周的学习情况,天天都是0节课啊!正好在学习Android自定义View,于是就想着自己去写了一个,这里先给出一张慕课网的图,和自己的效果图. yissan的博客,未经允许严禁转载 http://blog.csdn.net/yissan 2.实现分析 我们要实现这样一个折线统计图,必要的信息主要有下面几个 先看纵轴,纵轴需要的信息有最大值,还有用来确定每个间距代表的单位,比如最大值是100,我们还要有一个将值分为几份的数据.

自定义手势解锁锁控件

一.控件的使用 模仿市面上app的手势解锁功能,实现的小控件,将控件封装到了一个UIView上 二.核心原理技术 1.触摸事件 (1)UIView的触摸三个触摸响应事件:开始.移动.结束 (2)CGRectContainsPoint 判断触摸点的位置 2.Quartz2D绘图 (1)drawRect 的重绘 (2)UIBezierPath 贝塞尔曲线 3.block成功和失败的回调 三.实现思路 1.解锁键盘中的9个小图标,会根据验证过程而变化颜色,所以考虑用UIButton实现,因为UIBut

android自定义LinearLayout和View

自定义线性布局经常用到: 第一种是在扩展的LinearLayout构造函数中使用Inflater加载一个布局,并从中提取出相关的UI组件进行封装,形成一个独立的控件.在使用该控件时,由于它所有的子元素都是在运行时通过代码动态创建的,所以该控件只能以一个独立控件的形式在Layout文件中声明,例如: public class CustomLayout extends LinearLayout{ public CustomLayout(Context context){ LayoutInflater

Android自定义Viewgroup切换View带有吸附效果

1.概述 先上效果图 大概就是这个效果,先说说实现思路 1.首先我们要拿到图片的url(网络)或id.路径(本地),将View与数据进行绑定,写我们自己的Adapter 2.自定义Viewgroup将要显示的view进行布局,以及处理触摸事件进行逻辑处理 3.写切换回调 2.实现 1)自定义Adapter 这里我下载的网络图片,同样可以将图片放到res下设置ImageView的内容 public class DragPageViewAdapter { private static final S

Android进阶之自定义View实战(二)九宫格手势解锁实现

一.引言 在上篇博客Android进阶之自定义View实战(一)仿iOS UISwitch控件实现中我们主要介绍了自定义View的最基本的实现方法.作为自定义View的入门篇,仅仅介绍了Canvas的基本使用方法,而对用户交互层面仅仅处理了单击事件接口,在实际的业务中,常常涉及到手势操作,本篇博客以九宫格手势解锁View为例,来说明自定义View如何根据需求处理用户的手势操作.虽然九宫格手势解锁自定义View网上资料有很多,实现原理大同小异,但这里我只是根据自己觉得最优的思路来实现它,目的是让更

[iOS UI进阶 - 5.0] 手势解锁Demo

A.需求 1.九宫格手势解锁 2.使用了绘图和手势事件 code source: https://github.com/hellovoidworld/GestureUnlockDemo B.实现 使用按钮来处理每个圆点 使用代码生成按钮 取消按钮点击事件 设置普通状态和选中状态的背景图片 CGRectContainsPoint,移动到按钮范围内改变按钮为选中状态 按钮的连接:使用数组存储被选中的所有按钮,画上连线 已经连线的按钮不需要再连线 触摸结束清空连线和按钮选中状态 移动中也要画出线,最后

九点(九宫格)式手势解锁自定义view

周末闲着没事,写了个手势解锁的view,实现起来也蛮快的,半天多一点时间就完事.把源码和资源贴出来,给大家分享,希望对大家有用. 效果,就跟手机上的九点手势解锁一样,上个图吧: 过程嘛感觉确实没啥好讲的了,涉及的知识以前的博客都说过了,无非就是canva,paint,touch事件这些,画画圆圈画画线条,剩下的就是细节处理逻辑了.都在代码里,所以这里就主要是贴资源吧. 这个自定义view就一个类,源码如下: package com.cc.library.view; import android.

手势解锁自定义View

1 package com.rxx.view; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Timer; 6 import java.util.TimerTask; 7 import android.content.Context; 8 import android.graphics.Canvas; 9 import android.graphics.Color; 10 import an

Android自定义View的一般步骤

1.设置当前View自定义属性 需要在res的values文件夹下新建个attrs文件,在attrs文件中设置相关的自定义属性 设置自定义属性的名称 <!-- format属性可以用来限制当前自定义的属性是什么类型, 中间可以用 | 来连接,表示可以支持多种类型 --> <attr name="user_defined_attribute" format="color" /> <!-- 可以指定枚举类型,用来自定义一些需要用户选择的属性