Android APP數(shù)字解鎖實(shí)例詳解
Android APP數(shù)字上鎖
最近抽時(shí)間做了下數(shù)字解鎖的功能,手機(jī)有數(shù)字解鎖,App也可以做到,避免某些應(yīng)用隱私泄漏,一下就是實(shí)現(xiàn)效果圖:


序言:這兩天老大給了個(gè)任務(wù),說是做一個(gè)仿ios的數(shù)字鎖屏界面,心想著這種東西網(wǎng)上應(yīng)該有挺多的,然后就先百度了一把,誰知道案例好像少的可憐,然后帶著懷疑的心態(tài)去下載了千辛萬苦找到的“源碼”,看里面寫的,然后自己有點(diǎn)眉目了,就自己借著“源碼”的思路自己實(shí)現(xiàn)了一把,見上圖。
思路:
這里我們可以看成兩部分,一部分是上面的輸入的,另一部分是底部的按鍵。
先來看上面那部分,我們可以看成是TextView,然后響應(yīng)下面按鍵的動(dòng)作。下面這部分,圖中的每個(gè)按鈕都需要自己畫出來,難點(diǎn)就是根據(jù)第一個(gè)按鍵的坐標(biāo)(第一個(gè)坐標(biāo)我們初始化)算出每個(gè)按鍵的坐標(biāo),然后根據(jù)手指的觸摸屏事件來判斷點(diǎn)擊的是哪個(gè)按鍵
接下來我們來看核心代碼:
輸入框部分:
public class PasswordTextView extends TextView{
private final String sing = "*";//密文顯示的內(nèi)容
private String content = "";//顯示的內(nèi)容
//文本改變事件回調(diào)接口
private OnTextChangedListener onTextChangedListener;
/**
* Handler線程對(duì)象,用來更新密碼框的顯示內(nèi)容
* 實(shí)現(xiàn)將輸入的內(nèi)容顯示為密文
*/
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
//密文顯示
PasswordTextView.this.setText(sing);
//回調(diào)改變事件接口
if(onTextChangedListener != null){
onTextChangedListener.textChanged(content);
}
};
};
/**
* 構(gòu)造方法
* @param context
* @param attrs
*/
public PasswordTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 設(shè)置文本改變事件監(jiān)聽
* @param onTextChangedListener
*/
public void setOnTextChangedListener(OnTextChangedListener onTextChangedListener){
this.onTextChangedListener = onTextChangedListener;
}
/**
* 設(shè)置密碼框顯示的內(nèi)容
* @param text
*/
public void setTextContent(String text){
//獲得輸入的內(nèi)容
this.content = text;
if(!TextUtils.isEmpty(text)){
handler.sendEmptyMessage(0);//向Handler發(fā)送消息
}else{
this.setText("");
}
}
/**
* 獲取顯示的內(nèi)容
* @return
*/
public String getTextContent(){
return content;
}
/**
* 文本改變事件接口
*/
public interface OnTextChangedListener{
/**
* 密碼框文本改變時(shí)調(diào)用
* @param content
*/
public void textChanged(String content);
}
}
下面按鍵部分
public class NumericK eyboard extends View {
private int screen_width = 0;// 屏幕的寬度
private float first_x = 0;// 繪制1的x坐標(biāo)
private float first_y = 0;// 繪制1的y坐標(biāo)
private float[] xs = new float[3];//聲明數(shù)組保存每一列的圓心橫坐標(biāo)
private float[] ys = new float[4];//聲明數(shù)組保存每一排的圓心縱坐標(biāo)
private float circle_x, circle_y;//點(diǎn)擊處的圓心坐標(biāo)
private int number = -1;//點(diǎn)擊的數(shù)字
private OnNumberClick onNumberClick;//數(shù)字點(diǎn)擊事件
/*
* 判斷刷新數(shù)據(jù)
* -1 不進(jìn)行數(shù)據(jù)刷新
* 0 按下刷新
* 1 彈起刷新
*/
private int type = -1;
/**
* 構(gòu)造方法
*
* @param context
*/
public NumericKeyboard(Context context) {
super(context);
initData(context);// 初始化數(shù)據(jù)
}
public NumericKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
initData(context);// 初始化數(shù)據(jù)
}
/**
* 設(shè)置數(shù)字點(diǎn)擊事件
*
* @param onNumberClick
*/
public void setOnNumberClick(OnNumberClick onNumberClick) {
this.onNumberClick = onNumberClick;
}
// 初始化數(shù)據(jù)
private void initData(Context context) {
// 獲取屏幕的寬度
screen_width = SystemUtils.getSystemDisplay(context)[0];
// 獲取繪制1的x坐標(biāo)
first_x = screen_width / 4;
// 獲取繪制1的y坐標(biāo)
first_y = (SystemUtils.getSystemDisplay(context)[1] - SystemUtils.getSystemDisplay(context)[1] / 3) / 4;
//添加每一排的橫坐標(biāo)
xs[0] = first_x + 10;
xs[1] = first_x * 2 + 10;
xs[2] = first_x * 3 + 10;
//添加每一列的縱坐標(biāo)
ys[0] = 40 + first_y - 15;
ys[1] = 40 + first_y + first_x - 15;
ys[2] = 40 + first_y + first_x * 2 - 15;
ys[3] = 40 + first_y + first_x * 3 - 15;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 創(chuàng)建畫筆對(duì)象
Paint paint = new Paint();
paint.setColor(Color.BLACK);// 設(shè)置畫筆顏色
paint.setTextSize(40);// 設(shè)置字體大小
paint.setStrokeWidth(2);
// 繪制文本,注意是從坐標(biāo)開始往上繪制
// 這里較難的就是算坐標(biāo)
// 繪制第一排1,2,3
canvas.drawText("1", first_x, 40 + first_y, paint);
canvas.drawText("2", first_x * 2, 40 + first_y, paint);
canvas.drawText("3", first_x * 3, 40 + first_y, paint);
// 繪制第2排4,5,6
canvas.drawText("4", first_x, 40 + first_y + first_x, paint);
canvas.drawText("5", first_x * 2, 40 + first_y + first_x, paint);
canvas.drawText("6", first_x * 3, 40 + first_y + first_x, paint);
// 繪制第3排7,8,9
canvas.drawText("7", first_x, 40 + first_y + first_x * 2, paint);
canvas.drawText("8", first_x * 2, 40 + first_y + first_x * 2, paint);
canvas.drawText("9", first_x * 3, 40 + first_y + first_x * 2, paint);
// 繪制第4排0
canvas.drawText("0", first_x * 2, 40 + first_y + first_x * 3, paint);
//為每一個(gè)數(shù)字繪制一個(gè)圓
paint.setColor(Color.WHITE);//設(shè)置畫筆顏色
paint.setAntiAlias(true);//設(shè)置抗鋸齒
//設(shè)置繪制空心圓
paint.setStyle(Paint.Style.STROKE);
//依次繪制第一排的圓
canvas.drawCircle(first_x + 10, 40 + first_y - 15, 70, paint);
canvas.drawCircle(first_x * 2 + 10, 40 + first_y - 15, 70, paint);
canvas.drawCircle(first_x * 3 + 10, 40 + first_y - 15, 70, paint);
//依次繪制第2排的圓
canvas.drawCircle(first_x + 10, 40 + first_y + first_x - 15, 70, paint);
canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x - 15, 70, paint);
canvas.drawCircle(first_x * 3 + 10, 40 + first_y + first_x - 15, 70, paint);
//依次繪制第3排的圓
canvas.drawCircle(first_x + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
canvas.drawCircle(first_x * 3 + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
//繪制最后一個(gè)圓
canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x * 3 - 15, 70, paint);
//判斷是否點(diǎn)擊數(shù)字(點(diǎn)擊數(shù)字產(chǎn)生的漸變效果)
if (circle_x > 0 && circle_y > 0) {
if (type == 0) {//按下刷新
paint.setColor(Color.WHITE);//設(shè)置畫筆顏色
paint.setStyle(Paint.Style.FILL_AND_STROKE);//按下的時(shí)候繪制實(shí)心圓
canvas.drawCircle(circle_x, circle_y, 70, paint);//繪制圓
} else if (type == 1) {//彈起刷新
paint.setColor(Color.WHITE);//設(shè)置畫筆顏色
paint.setStyle(Paint.Style.STROKE);//彈起的時(shí)候再繪制空心圓
canvas.drawCircle(circle_x, circle_y, 70, paint);//繪制圓
//繪制完成后,重置
circle_x = 0;
circle_y = 0;
}
}
}
/**
* 獲取觸摸點(diǎn)擊事件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
//事件判斷
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
//判斷點(diǎn)擊的坐標(biāo)位置
float x = event.getX();//按下時(shí)的X坐標(biāo)
float y = event.getY();//按下時(shí)的Y坐標(biāo)
//判斷點(diǎn)擊的是哪一個(gè)數(shù)字圓
handleDown(x, y);
return true;
case MotionEvent.ACTION_UP://彈起
type = 1;//彈起刷新
invalidate();//刷新界面
//返回點(diǎn)擊的數(shù)字
if (onNumberClick != null && number != -1) {
onNumberClick.onNumberReturn(number);
}
setDefault();//恢復(fù)默認(rèn)
//發(fā)送輔助事件
sendAccessEvent(R.string.numeric_keyboard_up);
return true;
case MotionEvent.ACTION_CANCEL://取消
//恢復(fù)默認(rèn)值
setDefault();
return true;
}
return false;
}
/*
* 恢復(fù)默認(rèn)值
*/
private void setDefault() {
circle_x = 0;
circle_y = 0;
type = -1;
number = -1;
sendAccessEvent(R.string.numeric_keyboard_cancel);
}
/*
* 設(shè)置輔助功能描述
*/
private void sendAccessEvent(int resId) {
//設(shè)置描述
setContentDescription(getContext().getString(resId));
//發(fā)送輔助事件
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
setContentDescription(null);
}
/*
* 判斷點(diǎn)擊的是哪一個(gè)數(shù)字圓
*/
private void handleDown(float x, float y) {
//判斷點(diǎn)擊的是那一列的數(shù)據(jù)
if (xs[0] - 70 <= x && x <= xs[0] + 70) {//第一列
//獲取點(diǎn)擊處的圓心橫坐標(biāo)
circle_x = xs[0];
//判斷點(diǎn)擊的是哪一排
if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[0];
number = 1;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[1];
number = 4;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[2];
number = 7;//設(shè)置點(diǎn)擊的數(shù)字
}
} else if (xs[1] - 70 <= x && x <= xs[1] + 70) {//第2列
//獲取點(diǎn)擊處的圓心橫坐標(biāo)
circle_x = xs[1];
//判斷點(diǎn)擊的是哪一排
if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[0];
number = 2;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[1];
number = 5;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[2];
number = 8;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[3] - 70 <= y && ys[3] + 70 >= y) {//第4排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[3];
number = 0;//設(shè)置點(diǎn)擊的數(shù)字
}
} else if (xs[2] - 70 <= x && x <= xs[2] + 70) {//第3列
//獲取點(diǎn)擊處的圓心橫坐標(biāo)
circle_x = xs[2];
//判斷點(diǎn)擊的是哪一排
if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[0];
number = 3;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[1];
number = 6;//設(shè)置點(diǎn)擊的數(shù)字
} else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
//獲取點(diǎn)擊的數(shù)字圓的圓心縱坐標(biāo)
circle_y = ys[2];
number = 9;//設(shè)置點(diǎn)擊的數(shù)字
}
}
sendAccessEvent(R.string.numeric_keyboard_down);
type = 0;//按下刷新
//繪制點(diǎn)擊時(shí)的背景圓
invalidate();
}
/**
* 數(shù)字點(diǎn)擊事件
*/
public interface OnNumberClick {
/**
* 返回點(diǎn)擊的數(shù)字
*
* @param number
*/
public void onNumberReturn(int number);
}
}
上面說了,難點(diǎn)在于計(jì)算按鍵的位置,在這里我是根據(jù)我下載的demo里面的計(jì)算方式相應(yīng)的修改了,如果不明白android屏幕坐標(biāo)系的同學(xué)請(qǐng)看下面的文章:
參考:
Github下載地址:DEMO下載
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android中ImageView.src設(shè)置圖片拉伸、填滿控件的方法
最近公司有個(gè)需求,要展示客戶公司的企業(yè)形象,用一張圖片放在ImageView中實(shí)現(xiàn),但是發(fā)現(xiàn)圖片并沒有填滿,而是在上下邊上留出了一點(diǎn)空白,下面這篇文章主要跟大家介紹了Android中ImageView.src設(shè)置圖片拉伸、填滿控件的方法,需要的朋友可以參考下。2017-06-06
一文帶你了解Android中的網(wǎng)絡(luò)請(qǐng)求
安卓開發(fā)網(wǎng)絡(luò)請(qǐng)求可謂是安卓開發(fā)的靈魂,如果你不會(huì)網(wǎng)絡(luò)請(qǐng)求,那么你開發(fā)的應(yīng)用軟件就是一具沒有靈魂的枯骨。本文主要為大家介紹的是Android的網(wǎng)絡(luò)請(qǐng)求,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-11-11
phonegap教程使用jspdf庫在應(yīng)用中生成pdf文件(pdf生成方法)
在PhoneGap應(yīng)用中生成pdf文件,實(shí)現(xiàn)起來很簡(jiǎn)單,使用JSPDF這個(gè)標(biāo)準(zhǔn)的JavaScript類庫來實(shí)現(xiàn)這個(gè)功能2014-01-01
Android 夜間模式的實(shí)現(xiàn)代碼示例
本篇文章主要介紹了Android 夜間模式的實(shí)現(xiàn)代碼示例,實(shí)現(xiàn)能夠根據(jù)不同的設(shè)定,呈現(xiàn)不同風(fēng)格的界面給用戶,有興趣的可以了解一下。2017-03-03
android實(shí)現(xiàn)視頻的加密和解密(使用AES)
本篇文章主要介紹了android實(shí)現(xiàn)視頻的加密和解密(使用AES),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
Android中使用SQLite3 命令行查看內(nèi)嵌數(shù)據(jù)庫的方法
這篇文章主要介紹了Android中使用SQLite3 命令行查看內(nèi)嵌數(shù)據(jù)庫的方法的相關(guān)資料,需要的朋友可以參考下2015-12-12
android studio的使用sdk manager的方法
這篇文章主要介紹了android studio的使用sdk manager的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Android SharedPreferences實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)功能
這篇文章主要為大家詳細(xì)介紹了Android SharedPreferences實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android 手機(jī)衛(wèi)士實(shí)現(xiàn)平移動(dòng)畫示例
這篇文章主要介紹了Android 手機(jī)衛(wèi)士實(shí)現(xiàn)平移動(dòng)畫的實(shí)例代碼,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10

