关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android手势密码实现方案

    Android手势密码实现方案

    2014-11-11 00:00:00 出处:51CTO
    分享

    前段时间因产品需求,做了一个手势密码,跟支付宝的手势密码类似,这里跟大家分享交流一下我实现的方式吧。

    这篇来分享一下绘制手势密码的实现(主要是设置手势密码、校验手势密码):

    一、大致界面介绍:

    图1

    图2

    图3

    图4

    图1:手势密码绘制界面 【主要是绘制上方的9个提示图标和9个宫格密码图标】

    图2:设置手势密码 【监听手势的输入,TouchEvent的事件处理,获取输入的手势密码,同时显示在上方的提示区域】

    图3:再绘制一次,两次密码不一致提示界面 【这里在实现的时候,错误提示文字加了“左右晃动的动画”,错误路径颜色标记为红色】

    图4:校验手势密码,输入的密码错误,给予红色路径+错误文字提示

    二、实现思路:

    1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标;

    2. 手势密码绘制区域,用一个类(GestureContentView.java)来实现,它继承自ViewGroup里面, 添加9个ImageView来表示图标, 在onLayout()方法中设置它们的位置;

    3. 手势路径绘制, 用一个类(GestureDrawline.java)来实现,复写onTouchEvent()方法,在这个方法里面监听TouchEvent事件: ACTION_DOWN、ACTION_MOVE、ACTION_UP事件,来绘制手势连接不同点之间的路径;

    4. 9个点的对象,用一个类(GesturePoint.java)来实现,保存它的位置、状态、背景图片等相关信息;

    5. 手势密码的获取,判断手指当前的位置,根据滑动路径经过的点,按顺序保存绘制的点的顺序(这里的点顺序从上到下分别是:1,2,3,4,5,6,7,8,9),不能有重复的点。

    三、代码实现步骤:

    1.要用一个类来表示这9个点中的第一个点。里面保留有当前点的上下左右的各个位置等属性

    2.自定义GroupView,用来装9个点,9个点的显示是通过ImageView。复写onLayout这个方法,让点按需求排列

    3.定义一个可以画线的View,复写onTouchEvent方法,在这个方法里面进行画直线的操作

    4.判断用户手指当前的位置,取出当前的位置去与那9个点中的每个点的位置进行比较,假如用户点的位置在某一个点之内,那么当那个点置换背景图片。

    具体实现代码如下:

    1. LockIndicator.java 图案提示类

    package com.snda.fund.widget;
    
    import com.snda.fund.R;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Paint.Style;
    import android.graphics.drawable.Drawable;
    import android.os.PowerManager;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    
    /**
     * 
     * 手势密码图案提示
     * @author wulianghuan
     *
     */
    public class LockIndicator extends View {
    	private int numRow = 3;	// 行
    	private int numColum = 3; // 列
    	private int patternWidth = 40;
    	private int patternHeight = 40;
    	private int f = 5;
    	private int g = 5;
    	private int strokeWidth = 3;
    	private Paint paint = null;
    	private Drawable patternNoraml = null;
    	private Drawable patternPressed = null;
    	private String lockPassStr; // 手势密码
    
    	public LockIndicator(Context paramContext) {
    		super(paramContext);
    	}
    
    	public LockIndicator(Context paramContext, AttributeSet paramAttributeSet) {
    		super(paramContext, paramAttributeSet, 0);
    		paint = new Paint();
    		paint.setAntiAlias(true);
    		paint.setStrokeWidth(strokeWidth);
    		paint.setStyle(Paint.Style.STROKE);
    		patternNoraml = getResources().getDrawable(R.drawable.lock_pattern_node_normal);
    		patternPressed = getResources().getDrawable(R.drawable.lock_pattern_node_pressed);
    		if (patternPressed != null) {
    			patternWidth = patternPressed.getIntrinsicWidth();
    			patternHeight = patternPressed.getIntrinsicHeight();
    			this.f = (patternWidth / 4);
    			this.g = (patternHeight / 4);
    			patternPressed.setBounds(0, 0, patternWidth, patternHeight);
    			patternNoraml.setBounds(0, 0, patternWidth, patternHeight);
    		}
    	}
    
    	@Override
    	protected void onDraw(Canvas canvas) {
    		if ((patternPressed == null) || (patternNoraml == null)) {
    			return;
    		}
    		// 绘制3*3的图标
    		for (int i = 0; i < numRow; i++) {
    			for (int j = 0; j < numColum; j++) {
    				paint.setColor(-16777216);
    				int i1 = j * patternHeight + j * this.g;
    				int i2 = i * patternWidth + i * this.f;
    				canvas.save();
    				canvas.translate(i1, i2);
    				String curNum = String.valueOf(numColum * i + (j + 1));
    				if (!TextUtils.isEmpty(lockPassStr)) {
    					if (lockPassStr.indexOf(curNum) == -1) {
    						// 未选中
    						patternNoraml.draw(canvas);
    					} else {
    						// 被选中
    						patternPressed.draw(canvas);
    					}
    				} else {
    					// 重置状态
    					patternNoraml.draw(canvas);
    				}
    				canvas.restore();
    			}
    		}
    	}
    
    	@Override
    	protected void onMeasure(int paramInt1, int paramInt2) {
    		if (patternPressed != null)
    			setMeasuredDimension(numColum * patternHeight + this.g
    					* (-1 + numColum), numRow * patternWidth + this.f
    					* (-1 + numRow));
    	}
    
    	/**
    	 * 请求重新绘制
    	 * @param paramString 手势密码字符序列
    	 */
    	public void setPath(String paramString) {
    		lockPassStr = paramString;
    		invalidate();
    	}
    
    }

    2. GestureContentView.java 手势密码容器类

    它继承ViewGroup,通过addView()方法添加子viewe,手势密码的9个输入点(GesturePoint)、GestureDrawline手势密码路径都放在这个容器当中,下面是它的具体实现方法:

    package com.wujay.fund.widget;
    
    import java.util.ArrayList;
    import java.util.List;
    import android.content.Context;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import com.wujay.fund.R;
    import com.wujay.fund.common.AppUtil;
    import com.wujay.fund.entity.GesturePoint;
    import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
    
    /**
     * 手势密码容器类
     *
     */
    public class GestureContentView extends ViewGroup {
    
    	private int baseNum = 6;
    
    	private int[] screenDispaly;
    
    	/**
    	 * 每个点区域的宽度
    	 */
    	private int blockWidth;
    	/**
    	 * 声明一个集合用来封装坐标集合
    	 */
    	private List<GesturePoint> list;
    	private Context context;
    	private boolean isVerify;
    	private GestureDrawline gestureDrawline;
    
    	/**
    	 * 包含9个ImageView的容器,初始化
    	 * @param context
    	 * @param isVerify 是否为校验手势密码
    	 * @param passWord 用户传入密码
    	 * @param callBack 手势绘制完毕的回调
    	 */
    	public GestureContentView(Context context, boolean isVerify, String passWord, GestureCallBack callBack) {
    		super(context);
    		screenDispaly = AppUtil.getScreenDispaly(context);
    		blockWidth = screenDispaly[0]/3;
    		this.list = new ArrayList<GesturePoint>();
    		this.context = context;
    		this.isVerify = isVerify;
    		// 添加9个图标
    		addChild();
    		// 初始化一个可以画线的view
    		gestureDrawline = new GestureDrawline(context, list, isVerify, passWord, callBack);
    	}
    
    	private void addChild(){
    		for (int i = 0; i < 9; i++) {
    			ImageView image = new ImageView(context);
    			image.setBackgroundResource(R.drawable.gesture_node_normal);
    			this.addView(image);
    			invalidate();
    			// 第几行
    			int row = i / 3;
    			// 第几列
    			int col = i % 3;
    			// 定义点的每个属性
    			int leftX = col*blockWidth+blockWidth/baseNum;
    			int topY = row*blockWidth+blockWidth/baseNum;
    			int rightX = col*blockWidth+blockWidth-blockWidth/baseNum;
    			int bottomY = row*blockWidth+blockWidth-blockWidth/baseNum;
    			GesturePoint p = new GesturePoint(leftX, rightX, topY, bottomY, image,i+1);
    			this.list.add(p);
    		}
    	}
    
    	public void setParentView(ViewGroup parent){
    		// 得到屏幕的宽度
    		int width = screenDispaly[0];
    		LayoutParams layoutParams = new LayoutParams(width, width);
    		this.setLayoutParams(layoutParams);
    		gestureDrawline.setLayoutParams(layoutParams);
    		parent.addView(gestureDrawline);
    		parent.addView(this);
    	}
    
    	@Override
    	protected void onLayout(boolean changed, int l, int t, int r, int b) {
    		for (int i = 0; i < getChildCount(); i++) {
    			//第几行
    			int row = i/3;
    			//第几列
    			int col = i%3;
    			View v = getChildAt(i);
    			v.layout(col*blockWidth+blockWidth/baseNum, row*blockWidth+blockWidth/baseNum, 
    					col*blockWidth+blockWidth-blockWidth/baseNum, row*blockWidth+blockWidth-blockWidth/baseNum);
    		}
    	}
    
    	@Override
    	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    		// 遍历设置每个子view的大小
            for (int i = 0; i < getChildCount(); i++) {
                View v = getChildAt(i);
                v.measure(widthMeasureSpec, heightMeasureSpec);
            }
    	}
    
    	/**
    	 * 保留路径delayTime时间长
    	 * @param delayTime
    	 */
    	public void clearDrawlineState(long delayTime) {
    		gestureDrawline.clearDrawlineState(delayTime);
    	}
    
    }

    3. GestureDrawline.java 手势密码路径绘制类

    根据OnTouchEvent方法的不同事件,ACTION_DOWN、ACTION_MOVE、ACTION_UP分别处理不同的逻辑。

    package com.wujay.fund.widget;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import com.wujay.fund.common.AppUtil;
    import com.wujay.fund.common.Constants;
    import com.wujay.fund.entity.GesturePoint;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Paint.Style;
    import android.graphics.PorterDuff;
    import android.os.Handler;
    import android.util.Log;
    import android.util.Pair;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.Toast;
    
    /**
     * 手势密码路径绘制
     *
     */
    public class GestureDrawline extends View {
    	private int mov_x;// 声明起点坐标
    	private int mov_y;
    	private Paint paint;// 声明画笔
    	private Canvas canvas;// 画布
    	private Bitmap bitmap;// 位图
    	private List<GesturePoint> list;// 装有各个view坐标的集合
    	private List<Pair<GesturePoint, GesturePoint>> lineList;// 记录画过的线
    	private Map<String, GesturePoint> autoCheckPointMap;// 自动选中的情况点
    	private boolean isDrawEnable = true; // 是否允许绘制
    
    	/**
    	 * 屏幕的宽度和高度
    	 */
    	private int[] screenDispaly;
    
    	/**
    	 * 手指当前在哪个Point内
    	 */
    	private GesturePoint currentPoint;
    	/**
    	 * 用户绘图的回调
    	 */
    	private GestureCallBack callBack;
    
    	/**
    	 * 用户当前绘制的图形密码
    	 */
    	private StringBuilder passWordSb;
    
    	/**
    	 * 是否为校验
    	 */
    	private boolean isVerify;
    
    	/**
    	 * 用户传入的passWord
    	 */
    	private String passWord;
    
    	public GestureDrawline(Context context, List<GesturePoint> list, boolean isVerify,
    			String passWord, GestureCallBack callBack) {
    		super(context);
    		screenDispaly = AppUtil.getScreenDispaly(context);
    		paint = new Paint(Paint.DITHER_FLAG);// 创建一个画笔
    		bitmap = Bitmap.createBitmap(screenDispaly[0], screenDispaly[0], Bitmap.Config.ARGB_8888); // 设置位图的宽高
    		canvas = new Canvas();
    		canvas.setBitmap(bitmap);
    		paint.setStyle(Style.STROKE);// 设置非填充
    		paint.setStrokeWidth(10);// 笔宽5像素
    		paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
    		paint.setAntiAlias(true);// 不显示锯齿
    
    		this.list = list;
    		this.lineList = new ArrayList<Pair<GesturePoint, GesturePoint>>();
    
    		initAutoCheckPointMap();
    		this.callBack = callBack;
    
    		// 初始化密码缓存
    		this.isVerify = isVerify;
    		this.passWordSb = new StringBuilder();
    		this.passWord = passWord;
    	}
    
    	private void initAutoCheckPointMap() {
    		autoCheckPointMap = new HashMap<String,GesturePoint>();
    		autoCheckPointMap.put("1,3", getGesturePointByNum(2));
    		autoCheckPointMap.put("1,7", getGesturePointByNum(4));
    		autoCheckPointMap.put("1,9", getGesturePointByNum(5));
    		autoCheckPointMap.put("2,8", getGesturePointByNum(5));
    		autoCheckPointMap.put("3,7", getGesturePointByNum(5));
    		autoCheckPointMap.put("3,9", getGesturePointByNum(6));
    		autoCheckPointMap.put("4,6", getGesturePointByNum(5));
    		autoCheckPointMap.put("7,9", getGesturePointByNum(8));
    	}
    
    	private GesturePoint getGesturePointByNum(int num) {
    		for (GesturePoint point : list) {
    			if (point.getNum() == num) {
    				return point;
    			}
    		}
    		return null;
    	}
    
    	// 画位图
    	@Override
    	protected void onDraw(Canvas canvas) {
    		// super.onDraw(canvas);
    		canvas.drawBitmap(bitmap, 0, 0, null);
    	}
    
    	// 触摸事件
    	@Override
    	public boolean onTouchEvent(MotionEvent event) {
    		if (isDrawEnable == false) {
    			// 当期不允许绘制
    			return true;
    		}
    		paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			mov_x = (int) event.getX();
    			mov_y = (int) event.getY();
    			// 判断当前点击的位置是处于哪个点之内
    			currentPoint = getPointAt(mov_x, mov_y);
    			if (currentPoint != null) {
    				currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
    				passWordSb.append(currentPoint.getNum());
    			}
    			// canvas.drawPoint(mov_x, mov_y, paint);// 画点
    			invalidate();
    			break;
    		case MotionEvent.ACTION_MOVE:
    			clearScreenAndDrawList();
    
    			// 得到当前移动位置是处于哪个点内
    			GesturePoint pointAt = getPointAt((int) event.getX(), (int) event.getY());
    			// 代表当前用户手指处于点与点之前
    			if (currentPoint == null && pointAt == null) {
    				return true;
    			} else {// 代表用户的手指移动到了点上
    				if (currentPoint == null) {// 先判断当前的point是不是为null
    					// 假如为空,那么把手指移动到的点赋值给currentPoint
    					currentPoint = pointAt;
    					// 把currentPoint这个点设置选中为true;
    					currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
    					passWordSb.append(currentPoint.getNum());
    				}
    			}
    			if (pointAt == null || currentPoint.equals(pointAt) || Constants.POINT_STATE_SELECTED == pointAt.getPointState()) {
    				// 点击移动区域不在圆的区域,或者当前点击的点与当前移动到的点的位置相同,或者当前点击的点处于选中状态
    				// 那么以当前的点中心为起点,以手指移动位置为终点画线
    				canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), event.getX(), event.getY(), paint);// 画线
    			} else {
    				// 假如当前点击的点与当前移动到的点的位置不同
    				// 那么以前前点的中心为起点,以手移动到的点的位置画线
    				canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), pointAt.getCenterX(), pointAt.getCenterY(), paint);// 画线
    				pointAt.setPointState(Constants.POINT_STATE_SELECTED);
    
    				// 判断是否中间点需要选中
    				GesturePoint betweenPoint = getBetweenCheckPoint(currentPoint, pointAt);
    				if (betweenPoint != null && Constants.POINT_STATE_SELECTED != betweenPoint.getPointState()) {
    					// 存在中间点并且没有被选中
    					Pair<GesturePoint, GesturePoint> pair1 = new Pair<GesturePoint, GesturePoint>(currentPoint, betweenPoint);
    					lineList.add(pair1);
    					passWordSb.append(betweenPoint.getNum());
    					Pair<GesturePoint, GesturePoint> pair2 = new Pair<GesturePoint, GesturePoint>(betweenPoint, pointAt);
    					lineList.add(pair2);
    					passWordSb.append(pointAt.getNum());
    					// 设置中间点选中
    					betweenPoint.setPointState(Constants.POINT_STATE_SELECTED);
    					// 赋值当前的point;
    					currentPoint = pointAt;
    				} else {
    					Pair<GesturePoint, GesturePoint> pair = new Pair<GesturePoint, GesturePoint>(currentPoint, pointAt);
    					lineList.add(pair);
    					passWordSb.append(pointAt.getNum());
    					// 赋值当前的point;
    					currentPoint = pointAt;
    				}
    			}
    			invalidate();
    			break;
    		case MotionEvent.ACTION_UP:// 当手指抬起的时候
    			if (isVerify) {
    				// 手势密码校验
    				// 清掉屏幕上所有的线,只画上集合里面保存的线
    				if (passWord.equals(passWordSb.toString())) {
    					// 代表用户绘制的密码手势与传入的密码相同
    					callBack.checkedSuccess();
    				} else {
    					// 用户绘制的密码与传入的密码不同。
    					callBack.checkedFail();
    				}
    			} else {
    				callBack.onGestureCodeInput(passWordSb.toString());
    			}
    			break;
    		default:
    			break;
    		}
    		return true;
    	}
    
    	/**
    	 * 指定时间去清除绘制的状态
    	 * @param delayTime 延迟执行时间
    	 */
    	public void clearDrawlineState(long delayTime) {
    		if (delayTime > 0) {
    			// 绘制红色提示路线
    			isDrawEnable = false;
    			drawErrorPathTip();
    		}
    		new Handler().postDelayed(new clearStateRunnable(), delayTime);
    	}
    
    	/**
    	 * 清除绘制状态的线程
    	 */
    	final class clearStateRunnable implements Runnable {
    		public void run() {
    			// 重置passWordSb
    			passWordSb = new StringBuilder();
    			// 清空保存点的集合
    			lineList.clear();
    			// 重新绘制界面
    			clearScreenAndDrawList();
    			for (GesturePoint p : list) {
    				p.setPointState(Constants.POINT_STATE_NORMAL);
    			}
    			invalidate();
    			isDrawEnable = true;
    		}
    	}
    
    	/**
    	 * 通过点的位置去集合里面查找这个点是包含在哪个Point里面的
    	 * 
    	 * @param x
    	 * @param y
    	 * @return 假如没有找到,则返回null,代表用户当前移动的地方属于点与点之间
    	 */
    	private GesturePoint getPointAt(int x, int y) {
    
    		for (GesturePoint point : list) {
    			// 先判断x
    			int leftX = point.getLeftX();
    			int rightX = point.getRightX();
    			if (!(x >= leftX && x < rightX)) {
    				// 假如为假,则跳到下一个对比
    				continue;
    			}
    
    			int topY = point.getTopY();
    			int bottomY = point.getBottomY();
    			if (!(y >= topY && y < bottomY)) {
    				// 假如为假,则跳到下一个对比
    				continue;
    			}
    
    			// 假如执行到这,那么说明当前点击的点的位置在遍历到点的位置这个地方
    			return point;
    		}
    
    		return null;
    	}
    
    	private GesturePoint getBetweenCheckPoint(GesturePoint pointStart, GesturePoint pointEnd) {
    		int startNum = pointStart.getNum();
    		int endNum = pointEnd.getNum();
    		String key = null;
    		if (startNum < endNum) {
    			key = startNum + "," + endNum;
    		} else {
    			key = endNum + "," + startNum;
    		}
    		return autoCheckPointMap.get(key);
    	}
    
    	/**
    	 * 清掉屏幕上所有的线,然后画出集合里面的线
    	 */
    	private void clearScreenAndDrawList() {
    		canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    		for (Pair<GesturePoint, GesturePoint> pair : lineList) {
    			canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
    					pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
    		}
    	}
    
    	/**
    	 * 校验错误/两次绘制不一致提示
    	 */
    	private void drawErrorPathTip() {
    		canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    		paint.setColor(Color.rgb(154, 7, 21));// 设置默认线路颜色
    		for (Pair<GesturePoint, GesturePoint> pair : lineList) {
    			pair.first.setPointState(Constants.POINT_STATE_WRONG);
    			pair.second.setPointState(Constants.POINT_STATE_WRONG);
    			canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
    					pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
    		}
    		invalidate();
    	}
    
    	public interface GestureCallBack {
    
    		/**
    		 * 用户设置/输入了手势密码
    		 */
    		public abstract void onGestureCodeInput(String inputCode);
    
    		/**
    		 * 代表用户绘制的密码与传入的密码相同
    		 */
    		public abstract void checkedSuccess();
    
    		/**
    		 * 代表用户绘制的密码与传入的密码不相同
    		 */
    		public abstract void checkedFail();
    	}
    
    }

    4.GestureEditActivity.java 手势密码设置界面

    手势密码设置

    代码如下:

    package com.wujay.fund;
    
    import com.wujay.fund.R;
    import android.app.Activity;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.os.Bundle;
    import android.text.Html;
    import android.text.TextUtils;
    import android.view.KeyEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.FrameLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    import com.wujay.fund.common.Constants;
    import com.wujay.fund.widget.GestureContentView;
    import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
    import com.wujay.fund.widget.LockIndicator;
    
    /**
     * 
     * 手势密码设置界面
     *
     */
    public class GestureEditActivity extends Activity implements OnClickListener {
    	/** 手机号码*/
    	public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
    	/** 意图 */
    	public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
    	/** 首次提示绘制手势密码,可以选择跳过 */
    	public static final String PARAM_IS_FIRST_ADVICE = "PARAM_IS_FIRST_ADVICE";
    	private TextView mTextTitle;
    	private TextView mTextCancel;
    	private LockIndicator mLockIndicator;
    	private TextView mTextTip;
    	private FrameLayout mGestureContainer;
    	private GestureContentView mGestureContentView;
    	private TextView mTextReset;
    	private String mParamSetUpcode = null;
    	private String mParamPhoneNumber;
    	private boolean mIsFirstInput = true;
    	private String mFirstPassword = null;
    	private String mConfirmPassword = null;
    	private int mParamIntentCode;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_gesture_edit);
    		setUpViews();
    		setUpListeners();
    	}
    
    	private void setUpViews() {
    		mTextTitle = (TextView) findViewById(R.id.text_title);
    		mTextCancel = (TextView) findViewById(R.id.text_cancel);
    		mTextReset = (TextView) findViewById(R.id.text_reset);
    		mTextReset.setClickable(false);
    		mLockIndicator = (LockIndicator) findViewById(R.id.lock_indicator);
    		mTextTip = (TextView) findViewById(R.id.text_tip);
    		mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
    		// 初始化一个显示各个点的viewGroup
    		mGestureContentView = new GestureContentView(this, false, "", new GestureCallBack() {
    			@Override
    			public void onGestureCodeInput(String inputCode) {
    				if (!isInputPassValidate(inputCode)) {
    					mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>最少链接4个点, 请重新输入</font>"));
    					mGestureContentView.clearDrawlineState(0L);
    					return;
    				}
    				if (mIsFirstInput) {
    					mFirstPassword = inputCode;
    					updateCodeList(inputCode);
    					mGestureContentView.clearDrawlineState(0L);
    					mTextReset.setClickable(true);
    					mTextReset.setText(getString(R.string.reset_gesture_code));
    				} else {
    					if (inputCode.equals(mFirstPassword)) {
    							Toast.makeText(GestureEditActivity.this, "设置成功", Toast.LENGTH_SHORT).show();
    						mGestureContentView.clearDrawlineState(0L);
    						GestureEditActivity.this.finish();
    					} else {
    						mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>与上一次绘制不一致,请重新绘制</font>"));
    						// 左右移动动画
    						Animation shakeAnimation = AnimationUtils.loadAnimation(GestureEditActivity.this, R.anim.shake);
    						mTextTip.startAnimation(shakeAnimation);
    						// 保持绘制的线,1.5秒后清除
    						mGestureContentView.clearDrawlineState(1300L);
    					}
    				}
    				mIsFirstInput = false;
    			}
    
    			@Override
    			public void checkedSuccess() {
    
    			}
    
    			@Override
    			public void checkedFail() {
    
    			}
    		});
    		// 设置手势解锁显示到哪个布局里面
    		mGestureContentView.setParentView(mGestureContainer);
    		updateCodeList("");
    	}
    
    	private void setUpListeners() {
    		mTextCancel.setOnClickListener(this);
    		mTextReset.setOnClickListener(this);
    	}
    
    	private void updateCodeList(String inputCode) {
    		// 更新选择的图案
    		mLockIndicator.setPath(inputCode);
    	}
    
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.text_cancel:
    			this.finish();
    			break;
    		case R.id.text_reset:
    			mIsFirstInput = true;
    			updateCodeList("");
    			mTextTip.setText(getString(R.string.set_gesture_pattern));
    			break;
    		default:
    			break;
    		}
    	}
    
    	private boolean isInputPassValidate(String inputPassword) {
    		if (TextUtils.isEmpty(inputPassword) || inputPassword.length() < 4) {
    			return false;
    		}
    		return true;
    	}
    
    }

    5. GestureVerifyActivity.java 手势密码校验界面

    代码如下:

    package com.wujay.fund;
    
    import com.wujay.fund.R;
    import com.wujay.fund.widget.GestureContentView;
    import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.DialogInterface;
    import android.content.DialogInterface.OnClickListener;
    import android.content.Intent;
    import android.os.Bundle;
    import android.text.Html;
    import android.text.TextUtils;
    import android.view.KeyEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    
    /**
     * 
     * 手势绘制/校验界面
     *
     */
    public class GestureVerifyActivity extends Activity implements android.view.View.OnClickListener {
    	/** 手机号码*/
    	public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
    	/** 意图 */
    	public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
    	private RelativeLayout mTopLayout;
    	private TextView mTextTitle;
    	private TextView mTextCancel;
    	private ImageView mImgUserLogo;
    	private TextView mTextPhoneNumber;
    	private TextView mTextTip;
    	private FrameLayout mGestureContainer;
    	private GestureContentView mGestureContentView;
    	private TextView mTextForget;
    	private TextView mTextOther;
    	private String mParamPhoneNumber;
    	private long mExitTime = 0;
    	private int mParamIntentCode;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_gesture_verify);
    		ObtainExtraData();
    		setUpViews();
    		setUpListeners();
    	}
    
    	private void ObtainExtraData() {
    		mParamPhoneNumber = getIntent().getStringExtra(PARAM_PHONE_NUMBER);
    		mParamIntentCode = getIntent().getIntExtra(PARAM_INTENT_CODE, 0);
    	}
    
    	private void setUpViews() {
    		mTopLayout = (RelativeLayout) findViewById(R.id.top_layout);
    		mTextTitle = (TextView) findViewById(R.id.text_title);
    		mTextCancel = (TextView) findViewById(R.id.text_cancel);
    		mImgUserLogo = (ImageView) findViewById(R.id.user_logo);
    		mTextPhoneNumber = (TextView) findViewById(R.id.text_phone_number);
    		mTextTip = (TextView) findViewById(R.id.text_tip);
    		mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
    		mTextForget = (TextView) findViewById(R.id.text_forget_gesture);
    		mTextOther = (TextView) findViewById(R.id.text_other_account);
    
    		// 初始化一个显示各个点的viewGroup
    		mGestureContentView = new GestureContentView(this, true, "1235789",
    				new GestureCallBack() {
    
    					@Override
    					public void onGestureCodeInput(String inputCode) {
    
    					}
    
    					@Override
    					public void checkedSuccess() {
    						mGestureContentView.clearDrawlineState(0L);
    						Toast.makeText(GestureVerifyActivity.this, "密码正确", 1000).show();
    						GestureVerifyActivity.this.finish();
    					}
    
    					@Override
    					public void checkedFail() {
    						mGestureContentView.clearDrawlineState(1300L);
    						mTextTip.setVisibility(View.VISIBLE);
    						mTextTip.setText(Html
    								.fromHtml("<font color='#c70c1e'>密码错误</font>"));
    						// 左右移动动画
    						Animation shakeAnimation = AnimationUtils.loadAnimation(GestureVerifyActivity.this, R.anim.shake);
    						mTextTip.startAnimation(shakeAnimation);
    					}
    				});
    		// 设置手势解锁显示到哪个布局里面
    		mGestureContentView.setParentView(mGestureContainer);
    	}
    
    	private void setUpListeners() {
    		mTextCancel.setOnClickListener(this);
    		mTextForget.setOnClickListener(this);
    		mTextOther.setOnClickListener(this);
    	}
    
    	private String getProtectedMobile(String phoneNumber) {
    		if (TextUtils.isEmpty(phoneNumber) || phoneNumber.length() < 11) {
    			return "";
    		}
    		StringBuilder builder = new StringBuilder();
    		builder.append(phoneNumber.subSequence(0,3));
    		builder.append("****");
    		builder.append(phoneNumber.subSequence(7,11));
    		return builder.toString();
    	}
    
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.text_cancel:
    			this.finish();
    			break;
    		default:
    			break;
    		}
    	}
    
    }

    以上是手势密码实现的关键代码,我把项目中的模块代码整理出来,新建了一个project,供大家分享和交流

    源码下载地址:http://download.csdn.net/detail/wulianghuan/8115995

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    SQL汉字转换为拼音的函数

    windows 7系统无法运行Photoshop CS3的解决方法

    巧用MySQL加密函数对Web网站敏感数据进行保护

    MySQL基础知识简介

    Windows7和WinXP下如何实现不输密码自动登录系统的设置方法介绍

    windows 7系统ip地址冲突怎么办?windows 7系统IP地址冲突问题的

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。