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 linedCycles = new ArrayList();
	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  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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。