Android APP數字上鎖
最近抽時間做了下數字解鎖的功能,手機有數字解鎖,App也可以做到,避免某些應用隱私泄漏,一下就是實現效果圖:
序言:這兩天老大給了個任務,說是做一個仿ios的數字鎖定畫面,心想著這種東西網上應該有挺多的,然後就先百度了一把,誰知道案例好像少的可憐,然後帶著懷疑的心態去下載了千辛萬苦找到的“源碼”,看裡面寫的,然後自己有點眉目了,就自己藉著“源碼”的思路自己實現了一把,見上圖。
思路:
這裡我們可以看成兩部分,一部分是上面的輸入的,另一部分是底部的按鍵。
先來看上面那部分,我們可以看成是TextView,然後響應下面按鍵的動作。下面這部分,圖中的每個按鈕都需要自己畫出來,痛點就是根據第一個按鍵的座標(第一個座標我們初始化)算出每個按鍵的座標,然後根據手指的觸控螢幕事件來判斷點擊的是哪個按鍵
接下來我們來看核心代碼:
輸入框部分:
public class PasswordTextView extends TextView{ private final String sing = "*";//密文顯示的內容 private String content = "";//顯示的內容 //文本改變事件回調介面 private OnTextChangedListener onTextChangedListener; /** * Handler線程對象,用來更新密碼框的顯示內容 * 實現將輸入的內容顯示為密文 */ private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { //密文顯示 PasswordTextView.this.setText(sing); //回調改變事件介面 if(onTextChangedListener != null){ onTextChangedListener.textChanged(content); } }; }; /** * 構造方法 * @param context * @param attrs */ public PasswordTextView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 設定文本改變事件監聽 * @param onTextChangedListener */ public void setOnTextChangedListener(OnTextChangedListener onTextChangedListener){ this.onTextChangedListener = onTextChangedListener; } /** * 設定密碼框顯示的內容 * @param text */ public void setTextContent(String text){ //獲得輸入的內容 this.content = text; if(!TextUtils.isEmpty(text)){ handler.sendEmptyMessage(0);//向Handler發送訊息 }else{ this.setText(""); } } /** * 擷取顯示的內容 * @return */ public String getTextContent(){ return content; } /** * 文本改變事件介面 */ public interface OnTextChangedListener{ /** * 密碼框文本改變時調用 * @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座標 private float first_y = 0;// 繪製1的y座標 private float[] xs = new float[3];//聲明數組儲存每一列的圓心橫座標 private float[] ys = new float[4];//聲明數組儲存每一排的圓心縱座標 private float circle_x, circle_y;//點擊處的圓心座標 private int number = -1;//點擊的數字 private OnNumberClick onNumberClick;//數字點擊事件 /* * 判斷重新整理資料 * -1 不進行資料重新整理 * 0 按下重新整理 * 1 彈起重新整理 */ private int type = -1; /** * 構造方法 * * @param context */ public NumericKeyboard(Context context) { super(context); initData(context);// 初始化資料 } public NumericKeyboard(Context context, AttributeSet attrs) { super(context, attrs); initData(context);// 初始化資料 } /** * 設定數字點擊事件 * * @param onNumberClick */ public void setOnNumberClick(OnNumberClick onNumberClick) { this.onNumberClick = onNumberClick; } // 初始化資料 private void initData(Context context) { // 擷取螢幕的寬度 screen_width = SystemUtils.getSystemDisplay(context)[0]; // 擷取繪製1的x座標 first_x = screen_width / 4; // 擷取繪製1的y座標 first_y = (SystemUtils.getSystemDisplay(context)[1] - SystemUtils.getSystemDisplay(context)[1] / 3) / 4; //添加每一排的橫座標 xs[0] = first_x + 10; xs[1] = first_x * 2 + 10; xs[2] = first_x * 3 + 10; //添加每一列的縱座標 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); // 建立畫筆對象 Paint paint = new Paint(); paint.setColor(Color.BLACK);// 設定畫筆顏色 paint.setTextSize(40);// 設定字型大小 paint.setStrokeWidth(2); // 繪製文本,注意是從座標開始往上繪製 // 這裡較難的就是算座標 // 繪製第一排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); //為每一個數字繪製一個圓 paint.setColor(Color.WHITE);//設定畫筆顏色 paint.setAntiAlias(true);//設定消除鋸齒 //設定繪製空心圓 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); //繪製最後一個圓 canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x * 3 - 15, 70, paint); //判斷是否點擊數字(點擊數字產生的漸層效果) if (circle_x > 0 && circle_y > 0) { if (type == 0) {//按下重新整理 paint.setColor(Color.WHITE);//設定畫筆顏色 paint.setStyle(Paint.Style.FILL_AND_STROKE);//按下的時候繪製實心圓 canvas.drawCircle(circle_x, circle_y, 70, paint);//繪製圓 } else if (type == 1) {//彈起重新整理 paint.setColor(Color.WHITE);//設定畫筆顏色 paint.setStyle(Paint.Style.STROKE);//彈起的時候再繪製空心圓 canvas.drawCircle(circle_x, circle_y, 70, paint);//繪製圓 //繪製完成後,重設 circle_x = 0; circle_y = 0; } } } /** * 擷取觸摸點擊事件 */ @Override public boolean onTouchEvent(MotionEvent event) { //事件判斷 switch (event.getAction()) { case MotionEvent.ACTION_DOWN://按下 //判斷點擊的座標位置 float x = event.getX();//按下時的X座標 float y = event.getY();//按下時的Y座標 //判斷點擊的是哪一個數字圓 handleDown(x, y); return true; case MotionEvent.ACTION_UP://彈起 type = 1;//彈起重新整理 invalidate();//重新整理介面 //返回點擊的數字 if (onNumberClick != null && number != -1) { onNumberClick.onNumberReturn(number); } setDefault();//恢複預設 //發送輔助事件 sendAccessEvent(R.string.numeric_keyboard_up); return true; case MotionEvent.ACTION_CANCEL://取消 //恢複預設值 setDefault(); return true; } return false; } /* * 恢複預設值 */ private void setDefault() { circle_x = 0; circle_y = 0; type = -1; number = -1; sendAccessEvent(R.string.numeric_keyboard_cancel); } /* * 設定協助工具功能描述 */ private void sendAccessEvent(int resId) { //設定描述 setContentDescription(getContext().getString(resId)); //發送輔助事件 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); setContentDescription(null); } /* * 判斷點擊的是哪一個數字圓 */ private void handleDown(float x, float y) { //判斷點擊的是那一列的資料 if (xs[0] - 70 <= x && x <= xs[0] + 70) {//第一列 //擷取點擊處的圓心橫座標 circle_x = xs[0]; //判斷點擊的是哪一排 if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[0]; number = 1;//設定點擊的數字 } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[1]; number = 4;//設定點擊的數字 } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[2]; number = 7;//設定點擊的數字 } } else if (xs[1] - 70 <= x && x <= xs[1] + 70) {//第2列 //擷取點擊處的圓心橫座標 circle_x = xs[1]; //判斷點擊的是哪一排 if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[0]; number = 2;//設定點擊的數字 } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[1]; number = 5;//設定點擊的數字 } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[2]; number = 8;//設定點擊的數字 } else if (ys[3] - 70 <= y && ys[3] + 70 >= y) {//第4排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[3]; number = 0;//設定點擊的數字 } } else if (xs[2] - 70 <= x && x <= xs[2] + 70) {//第3列 //擷取點擊處的圓心橫座標 circle_x = xs[2]; //判斷點擊的是哪一排 if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[0]; number = 3;//設定點擊的數字 } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[1]; number = 6;//設定點擊的數字 } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排 //擷取點擊的數字圓的圓心縱座標 circle_y = ys[2]; number = 9;//設定點擊的數字 } } sendAccessEvent(R.string.numeric_keyboard_down); type = 0;//按下重新整理 //繪製點擊時的背景圓 invalidate(); } /** * 數字點擊事件 */ public interface OnNumberClick { /** * 返回點擊的數字 * * @param number */ public void onNumberReturn(int number); }}
上面說了,痛點在於計算按鍵的位置,在這裡我是根據我下載的demo裡面的計算方式相應的修改了,如果不明白android螢幕座標系的同學請看下面的文章:
參考:
android座標系詳解
Github下載地址:DEMO下載
感謝閱讀,希望能協助到大家,謝謝大家對本站的支援!