Android自定義UI手勢密碼改進版
更新時間:2016年10月31日 14:38:23 作者:Saflyer
這篇文章主要為大家詳細介紹了改進版的Android自定義UI手勢密碼功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
接著第一個Android UI手勢密碼設計的基礎上繼續(xù)改進,效果圖如下

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="請輸入密碼" android:id="@+id/text" /> <com.example.lockpatterview.LockPatterView android:id="@+id/lock" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> </LinearLayout>
MainActivity
package com.example.lockpatterview;
import com.example.lockpatterview.LockPatterView.OnPatterChangeLister;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
public class MainActivity extends Activity implements OnPatterChangeLister {
LockPatterView lock;
TextView text;
String p = "14789";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
lock = (LockPatterView) findViewById(R.id.lock);
lock.SetOnPatterChangeLister(this);
}
@Override
public void onPatterChange(String passwordStr) {
if (!TextUtils.isEmpty(passwordStr)) {
if (passwordStr.equals(p)) {
text.setText(passwordStr);
} else {
text.setText("密碼錯誤");
lock.errorPoint();
}
}else {
Toast.makeText(MainActivity.this, "至少連接5點", 0).show();
}
}
@Override
public void onPatterStart(boolean isStart) {
if (isStart) {
text.setText("請繪制圖案");
}
}
}
LockPatterView
package com.example.lockpatterview;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class LockPatterView extends View {
private static final int POINT_SIZE = 5;
private Point[][] points = new Point[3][3];
private Matrix matrix = new Matrix();
private float width, height, offstartY, moveX, moveY;;
private Bitmap bitmap_pressed, bitmap_normal, bitmap_error, bitmap_line,
bitmap_line_error;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private List<Point> pointList = new ArrayList<LockPatterView.Point>();
private OnPatterChangeLister onPatterChangeLister;
/**
* 構造函數(shù)
*/
public LockPatterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LockPatterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LockPatterView(Context context) {
super(context);
}
/*********************************************************
* 繪制9宮格
* movePoint代表鼠標在移動,但是不是9宮格里面的點
* isInit是否初始化過9個點
* isSelect 點位是否被選中狀態(tài)
* isFinish 是否繪制完畢
*/
private boolean isInit, isSelect, isFinish, movePoint;
@Override
protected void onDraw(Canvas canvas) {
// 第一次沒有初始化就進行初始化,一旦初始化就不在初始化工作了,isInit的意思是---默認沒有初始化過
if (!isInit) {
// 初始化9個點
initPoints();
}
// 繪制9個點
points2Canvas(canvas);
if (pointList.size() > 0) {
Point a = pointList.get(0);
// 繪制九宮格坐標點
for (int i = 0; i < pointList.size(); i++) {
Point b = pointList.get(i);
line2Canvas(canvas, a, b);
a = b;
}
// 繪制鼠標坐標點
if (movePoint) {
line2Canvas(canvas, a, new Point(moveX, moveY));
}
}
}
/**
* 初始化9個點位 獲取點位的3種狀態(tài) 線的2種狀態(tài) 以及9點的坐標位置 以及初始化密碼操作 isInit=
* true設置狀態(tài)--下次不必初始化話工作了
*/
private void initPoints() {
// 獲取布局寬高
width = getWidth();
height = getHeight();
// 橫屏和豎屏
offstartY = (height - width) / 2;
// 圖片資源
bitmap_normal = BitmapFactory.decodeResource(getResources(),
R.drawable.btn_circle_normal);
bitmap_pressed = BitmapFactory.decodeResource(getResources(),
R.drawable.btn_circle_pressed);
bitmap_error = BitmapFactory.decodeResource(getResources(),
R.drawable.btn_circle_selected);
bitmap_line = BitmapFactory.decodeResource(getResources(),
R.drawable.ddd);
bitmap_line_error = BitmapFactory.decodeResource(getResources(),
R.drawable.qqq);
points[0][0] = new Point(width / 4, offstartY + width / 4);
points[0][1] = new Point(width / 2, offstartY + width / 4);
points[0][2] = new Point(width / 4 * 3, offstartY + width / 4);
points[1][0] = new Point(width / 4, offstartY + width / 4 * 2);
points[1][1] = new Point(width / 2, offstartY + width / 4 * 2);
points[1][2] = new Point(width / 4 * 3, offstartY + width / 4 * 2);
points[2][0] = new Point(width / 4, offstartY + width / 4 * 3);
points[2][1] = new Point(width / 2, offstartY + width / 4 * 3);
points[2][2] = new Point(width / 4 * 3, offstartY + width / 4 * 3);
// 設置密碼1--9
int index = 1;
for (Point[] points : this.points) {
for (Point point : points) {
point.index = index;
index++;
}
}
// 初始化完成
isInit = true;
}
/**
* 將9個點繪制到畫布 循環(huán)遍歷9個點位, 根據(jù)3種不同的狀態(tài)繪制3種不同的9個點位
*/
private void points2Canvas(Canvas canvas) {
// 循環(huán)遍歷9個點位
for (int i = 0; i < points.length; i++) {
// 循環(huán)遍歷每行的3個點位
for (int j = 0; j < points[i].length; j++) {
// 獲取依次的某個點位
Point point = points[i][j];
if (point.state == Point.STATE_PRESSED) {
// (Bitmap bitmap, float left, float top, Paint paint)
canvas.drawBitmap(bitmap_pressed,
point.x - bitmap_normal.getWidth() / 2, point.y
- bitmap_normal.getHeight() / 2, paint);
} else if (point.state == Point.STATE_ERROR) {
canvas.drawBitmap(bitmap_error,
point.x - bitmap_normal.getWidth() / 2, point.y
- bitmap_normal.getHeight() / 2, paint);
} else {
canvas.drawBitmap(bitmap_normal,
point.x - bitmap_normal.getWidth() / 2, point.y
- bitmap_normal.getHeight() / 2, paint);
}
}
}
}
/**
* 畫線
*/
public void line2Canvas(Canvas canvas, Point a, Point b) {
// 線的長度--2點之間的距離
float linelength = (float) Point.distance(a, b);
// 獲取2點之間的角度
float degress = getDegrees(a, b);
//根據(jù)a點進行旋轉
canvas.rotate(degress, a.x, a.y);
if (a.state == Point.STATE_PRESSED) {
// xy方向上的縮放比例
matrix.setScale(linelength / bitmap_line.getWidth(), 1);
matrix.postTranslate(a.x - bitmap_line.getWidth() / 2, a.y
- bitmap_line.getHeight() / 2);
canvas.drawBitmap(bitmap_line, matrix, paint);
} else {
matrix.setScale(linelength / bitmap_line.getWidth(), 1);
matrix.postTranslate(a.x - bitmap_line.getWidth() / 2, a.y
- bitmap_line.getHeight() / 2);
canvas.drawBitmap(bitmap_line_error, matrix, paint);
}
//畫線完畢回歸角度
canvas.rotate(-degress, a.x, a.y);
}
// 獲取角度
public float getDegrees(Point pointA, Point pointB) {
return (float) Math.toDegrees(Math.atan2(pointB.y - pointA.y, pointB.x
- pointA.x));
}
/****************************************************************************
* onTouch事件處理
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
moveX = event.getX();
moveY = event.getY();
movePoint = false;
isFinish = false;
Point point = null;
switch (event.getAction()) {
//只要按下操作,就代表重新繪制界面
case MotionEvent.ACTION_DOWN:
if (onPatterChangeLister != null) {
onPatterChangeLister.onPatterStart(true);
}
// 每次按下,都需要清空之前的集合
resetPoint();
// 檢測是不是在九宮格內(nèi)
point = chechSelectPoint();
if (point != null) {
//如果按下的位置在9宮格內(nèi),就改成狀態(tài)為true
isSelect = true;
}
break;
case MotionEvent.ACTION_MOVE:
if (isSelect) {
// 檢測是不是在九宮格內(nèi)
point = chechSelectPoint();
if (point == null) {
movePoint = true;
}
}
break;
case MotionEvent.ACTION_UP:
//繪制完畢,點位狀態(tài)改為未選中
isFinish = true;
isSelect = false;
break;
}
// 如果沒有繪制完畢,如果九宮格處于選中狀態(tài)
if (!isFinish && isSelect && point != null) {
// 交叉點
if (crossPoint(point)) {
movePoint = true;
} else {// 新點
point.state = Point.STATE_PRESSED;
pointList.add(point);
}
}
// 繪制結束
if (isFinish) {
// 繪制不成立
if (pointList.size() == 1) {
// resetPoint();
errorPoint();
} else if (pointList.size() < POINT_SIZE && pointList.size() > 0) {// 繪制錯誤
errorPoint();
if (onPatterChangeLister != null) {
onPatterChangeLister.onPatterChange(null);
}
} else {
if (onPatterChangeLister != null) {
String pass = "";
for (int i = 0; i < pointList.size(); i++) {
pass = pass + pointList.get(i).index;
}
if (!TextUtils.isEmpty(pass)) {
onPatterChangeLister.onPatterChange(pass);
}
}
}
}
postInvalidate();
return true;
}
/**
* 重新繪制
*/
public void resetPoint() {
for (int i = 0; i < pointList.size(); i++) {
Point point = pointList.get(i);
point.state = Point.STATE_NORMAL;
}
pointList.clear();
}
/**
* 檢查是否選中
*/
private Point chechSelectPoint() {
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
Point point = points[i][j];
if (Point.with(point.x, point.y, bitmap_normal.getWidth() / 2,
moveX, moveY)) {
return point;
}
}
}
return null;
}
/**
* 交叉點
*/
private boolean crossPoint(Point point) {
if (pointList.contains(point)) {
return true;
} else {
return false;
}
}
/**
* 繪制錯誤
*/
public void errorPoint() {
for (Point point : pointList) {
point.state = Point.STATE_ERROR;
}
}
/***********************************************************************
* 自定義的點
*/
public static class Point {
// 正常
public static int STATE_NORMAL = 0;
// 選中
public static int STATE_PRESSED = 1;
// 錯誤
public static int STATE_ERROR = 2;
public float x, y;
public int index = 0, state = 0;
public Point() {
};
public Point(float x, float y) {
this.x = x;
this.y = y;
}
/**
* 兩點之間的距離
*/
public static double distance(Point a, Point b) {
return Math.sqrt(Math.abs(a.x - b.x) * Math.abs(a.x - b.x)
+ Math.abs(a.y - b.y) * Math.abs(a.y - b.y));
}
/**
*/
public static boolean with(float paintX, float pointY, float r,
float moveX, float moveY) {
return Math.sqrt((paintX - moveX) * (paintX - moveX)
+ (pointY - moveY) * (pointY - moveY)) < r;
}
}
/**
* 圖案監(jiān)聽器
*/
public static interface OnPatterChangeLister {
void onPatterChange(String passwordStr);
void onPatterStart(boolean isStart);
}
/**
* 設置圖案監(jiān)聽器
*/
public void SetOnPatterChangeLister(OnPatterChangeLister changeLister) {
if (changeLister != null) {
this.onPatterChangeLister = changeLister;
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android RecyclerView網(wǎng)格布局示例解析
這篇文章主要介紹了Android RecyclerView網(wǎng)格布局示例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-12-12
android 網(wǎng)絡編程之網(wǎng)絡通信幾種方式實例分享
這篇文章主要介紹了android 網(wǎng)絡編程之網(wǎng)絡通信幾種方式,有需要的朋友可以參考一下2013-12-12
Android應用中使用Fragment組件的一些問題及解決方案總結
這里我們講的Fragment主要探討的是support庫中的Fragment,包括Fragment常遇到的crash崩潰問題,嵌套Fragment收不到onActivityResult()回調(diào)以及一些常用tips等,需要的朋友可以參考下2016-05-05

