Android實現九宮格解鎖
相信大家都有使用九宮格解鎖,比如在設置手機安全項目中,可以使用九宮格解鎖,提高安全性,以及在使用支付功能的時候,為了提高安全使用九宮鎖,今天就為大家介紹Android實現九宮格的方法,分享給大家供大家參考。具體如下:
運行效果截圖如下:
具體代碼如下:
布局文件如下:
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.xuliugen.jiugongge.SudokuView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
從布局文件中可以看出需要自定義一個View用于繪制九宮格圖案:
SudokuView.java
package com.xuliugen.jiugongge; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; public class SudokuView extends View { private static final int DEFALUT_CELL_WIDTH = 60; //默認的cell寬度 private static final int DEFALUT_CELL_STROKE_WIDTH = 2; private static final int DEFALUT_SPACE = DEFALUT_CELL_WIDTH >> 1; private Cell mCells[] = new Cell[9]; // 九宮格:定義用于存放九個數組 private int mCellWidth; private int mCellRadius; private int mCellStrokeWidth; private int mSpace; private Paint mPaintNormal; private Paint mPaintSelected; private int mWidth; private int mHeight; private float mCurrentX; private float mCurrentY; private boolean mFinish = false; private StringBuffer mSbSelected = new StringBuffer(20); /** * 下邊是三個構造方法:每一個構造方法中有一個初始化操作 */ public SudokuView(Context context) { super(context); init(); } public SudokuView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SudokuView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 初始化操作 */ private void init() { mCellWidth = DensityUtil.dip2px(getContext(), DEFALUT_CELL_WIDTH); mCellRadius = DensityUtil.dip2px(getContext(), DEFALUT_CELL_WIDTH >> 1); mCellStrokeWidth = DensityUtil.dip2px(getContext(), DEFALUT_CELL_STROKE_WIDTH); mSpace = DensityUtil.dip2px(getContext(), DEFALUT_SPACE); mPaintNormal = new Paint(); mPaintNormal.setColor(Color.WHITE); mPaintNormal.setStrokeWidth(mCellStrokeWidth); mPaintNormal.setStyle(Paint.Style.STROKE); mPaintNormal.setAntiAlias(true); mPaintSelected = new Paint(); mPaintSelected.setColor(Color.CYAN); mPaintSelected.setStrokeWidth(mCellStrokeWidth); mPaintSelected.setStyle(Paint.Style.STROKE); mPaintSelected.setAntiAlias(true); Cell cell; float x; float y; for (int i = 0; i < 9; i++) { x = mSpace * (i % 3 + 1) + mCellRadius + mCellWidth * (i % 3); y = mSpace * (i / 3 + 1) + mCellRadius + mCellWidth * (i / 3); cell = new Cell(x, y); mCells[i] = cell; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawCell(canvas); drawLine(canvas); } private void drawCell(Canvas canvas) { for (int i = 0; i < 9; i++) { canvas.drawCircle(mCells[i].getCenterX(), mCells[i].getCenterY(), mCellRadius, mCells[i].isSelected() ? mPaintSelected : mPaintNormal); } } private void drawLine(Canvas canvas) { if ("".equals(mSbSelected.toString())) { return; } String[] selectedIndexs = mSbSelected.toString().split(","); Cell cell = mCells[Integer.valueOf(selectedIndexs[0])]; Cell nextCell; if (selectedIndexs.length > 1) { for (int i = 1; i < selectedIndexs.length; i++) { nextCell = mCells[Integer.valueOf(selectedIndexs[i])]; canvas.drawLine(cell.getCenterX(), cell.getCenterY(), nextCell.getCenterX(), nextCell.getCenterY(), mPaintSelected); cell = nextCell; } } if (!mFinish) { canvas.drawLine(cell.getCenterX(), cell.getCenterY(), mCurrentX, mCurrentY, mPaintSelected); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mWidth = getRealSize(widthMeasureSpec); mHeight = getRealSize(heightMeasureSpec); setMeasuredDimension(mWidth, mWidth); } private int getRealSize(int measureSpc) { int result; int mode = MeasureSpec.getMode(measureSpc); int size = MeasureSpec.getSize(measureSpc); if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) { result = mCellWidth * 3 + mSpace * 4; } else { result = size; } return result; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (mFinish) { for (int i = 0; i < 9; i++) { mCells[i].setSelected(false); } mFinish = false; mSbSelected.delete(0, mSbSelected.length()); invalidate(); return false; } handleDownEvent(event); break; case MotionEvent.ACTION_UP: mFinish = true; Toast.makeText(getContext(), mSbSelected.toString(), Toast.LENGTH_SHORT).show(); break; case MotionEvent.ACTION_MOVE: handleMoveEvent(event); break; } return true; } private void handleMoveEvent(MotionEvent event) { int index = findCellIndex(event.getX(), event.getY()); if (index != -1) { mCells[index].setSelected(true); mSbSelected.append(index).append(","); } invalidate(); mCurrentX = event.getX(); mCurrentY = event.getY(); } private void handleDownEvent(MotionEvent event) { int index = findCellIndex(event.getX(), event.getY()); if (index != -1) { mCells[index].setSelected(true); mSbSelected.append(index).append(","); invalidate(); } mCurrentX = event.getX(); mCurrentY = event.getY(); } private int findCellIndex(float x, float y) { float cellX; float cellY; int result = -1; for (int i = 0; i < 9; i++) { if (mCells[i].isSelected()) { continue; } cellX = mCells[i].getCenterX(); cellY = mCells[i].getCenterY(); float tempX = cellX - x; float tempY = cellY - y; float distance = (float) Math.sqrt(tempX * tempX + tempY * tempY); if (distance < mCellRadius) { result = i; break; } } return result; } }
MainActivity.java如下:
package com.xuliugen.jiugongge; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
另外還需要一個存放圓圈的Javabean
package com.xuliugen.jiugongge; /** * 代表每一個九宮格圓圈的Javabean * @author xuliugenpc */ public class Cell { private float centerX; private float centerY; private boolean selected; public Cell(float x, float y) { centerX = x; centerY = y; } public float getCenterX() { return centerX; } public void setCenterX(float centerX) { this.centerX = centerX; } public float getCenterY() { return centerY; } public void setCenterY(float centerY) { this.centerY = centerY; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } }
像素轉換的工具類:
package com.xuliugen.jiugongge; import android.content.Context; /** * 手機屏幕px轉dp和dp轉px工具類 * @author xuliugenpc */ public class DensityUtil { private static float scale; /** * 根據手機的分辨率從 dp 的單位 轉成為 px(像素) */ public static int dip2px(Context context, float dpValue) { if (scale == 0) { scale = context.getResources().getDisplayMetrics().density; } return (int) (dpValue * scale + 0.5f); } /** * 根據手機的分辨率從 px(像素) 的單位 轉成為 dp */ public static int px2dip(Context context, float pxValue) { if (scale == 0) { scale = context.getResources().getDisplayMetrics().density; } return (int) (pxValue / scale + 0.5f); } }
以上就是Android實現九宮格解鎖的方法,希望本文所述對大家學習有所幫助。
相關文章
Android RecycleView使用(CheckBox全選、反選、單選)
這篇文章主要為大家詳細介紹了Android RecycleView使用,CheckBox全選、反選、單選效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09Android liveData與viewBinding使用教程
LiveData是一種可觀察的數據存儲器類,LiveData使用觀察者模式,每當數據發(fā)生變化時,LiveData會通知 Observer對象,我們可以在這些 Observer 對象中更新UI,ViewModel對象為特定的界面組件提供數據,并包含數據處理業(yè)務邏輯,會配合LiveData一起使用2022-11-11基于Android中Webview使用自定義的javascript進行回調的問題詳解
本篇文章對Android中Webview使用自定義的javascript進行回調的問題進行了詳細的分析介紹。需要的朋友參考下2013-05-05android使用NotificationListenerService監(jiān)聽通知欄消息
本篇文章主要介紹了android使用NotificationListenerService監(jiān)聽通知欄消息,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-01-01Android Compose自定義TextField實現自定義的輸入框
眾所周知Compose中默認的TextField和OutlineTextField樣式并不能滿足所有的使用場景,所以自定義TextField就成了必備技能。本文將自定義TextField實現自定義的輸入框,感興趣的可以了解一下2022-03-03