android自定義View實現(xiàn)手勢解鎖
有時候為了程序的安全性,我們經(jīng)常要采取一些安全措施,就像我們常用的支付寶那樣,隔一定的時間再回到應用程序時會讓用戶利用手勢去解鎖應用程序,最近由于項目需求,也要求做這樣一個功能,當用戶切出本應用程序15分鐘后回來,讓用戶手勢解鎖,整個需求的難點就在如何實現(xiàn)這個手勢鎖,開始一點頭緒也沒有,沒有一點思路去實現(xiàn)這個手勢解鎖功能,在google了一番后看了一篇非常好的博客后,按照博主的思路的確是可以實現(xiàn)一個十分不錯的手勢鎖View,也參考了下那位大神的代碼,下面是我根據(jù)他的思路和代碼片段實現(xiàn)的一個自定義手勢解鎖 View,先看效果圖.
這是自定義View的初始效果圖:
以下是繪制手勢時的效果圖:
下面是實現(xiàn)的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 { /** * 不同狀態(tài)的畫筆 */ 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<Integer> linedCycles = new ArrayList<Integer>(); private OnGestureFinishListener onGestureFinishListener; private String key; private int eventX, eventY; private boolean canContinue = true; private boolean result; private Timer timer; /** * 不同狀態(tài)下的色值 */ 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; } } } } /** * 繪制所需要繪制的內(nèi)容 */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); for (int i = 0; i < cycles.length; i++) { if (!canContinue && !result) { paintOnTouch.setColor(ERROR_COLOR); paintInnerCycle.setColor(ERROR_COLOR); paintLines.setColor(ERROR_COLOR); } else if (cycles[i].isOnTouch()) { paintOnTouch.setColor(OUT_CYCLE_ONTOUCH); paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); paintLines.setColor(LINE_COLOR); } else { paintNormal.setColor(OUT_CYCLE_NORMAL); paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH); paintLines.setColor(LINE_COLOR); } if (cycles[i].isOnTouch()) { canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintOnTouch); drawInnerBuleCycle(cycles[i], canvas); } else { canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintNormal); } } drawLine(canvas); } /** * 繪制大圓里的小圓 * * @param canvas */ private void drawInnerBuleCycle(MyCycle cycle, Canvas canvas) { canvas.drawCircle(cycle.getOx(), cycle.getOy(), cycle.getR() / 3, paintInnerCycle); } private void drawLine(Canvas canvas) { linePath.reset(); if (linedCycles.size() > 0) { for (int i = 0; i < linedCycles.size(); i++) { int index = linedCycles.get(i); if (i == 0) { // 設(shè)置為整條路徑的起點 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); } } /** * 根據(jù)手擇時觸摸點的不同,修改對應的狀態(tài)值 */ @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() { // 回到初始狀態(tài) 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事件,根據(jù)不同的事件修改MyCircle實例的狀態(tài),并調(diào)用更新invaildate更新View
3.重寫onDraw()方法,根據(jù)不同的狀態(tài)去重新繪制整個View
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Flutter?DateTime獲取本月的開始時間與結(jié)束時間方法
這篇文章主要為大家介紹了Flutter?DateTime獲取本月的開始時間與結(jié)束時間方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2023-05-05Andriod 讀取網(wǎng)絡(luò)圖片實例代碼解析
Android手機上,我們經(jīng)常用imageview顯示圖片,通過本文學習獲取網(wǎng)絡(luò)圖片并顯示在imageview中,對android讀取網(wǎng)絡(luò)圖片相關(guān)知識感興趣的朋友一起學習吧2016-02-02利用Jetpack?Compose實現(xiàn)繪制五角星效果
這篇文章主要為大家介紹了Jetpack?Compose如何使用自定義操作符實現(xiàn)繪制五角星效果,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2022-04-04Android 利用反射+try catch實現(xiàn)sdk按需引入依賴庫的方法
這篇文章主要介紹了Android 利用反射+try catch來實現(xiàn)sdk按需引入依賴庫,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11Android使用AnimationDrawable實現(xiàn)閃爍紅光動畫效果(案例詳解)
這篇文章主要介紹了Android使用AnimationDrawable實現(xiàn)閃爍紅光動畫效果,實現(xiàn)閃爍紅光效果可以使用Android中的Animation和Drawable資源,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-06-06Android程序開發(fā)之防止密碼輸入錯誤 密碼明文顯示功能
在使用App的時候,首次登錄都需要用戶輸入密碼的,有些朋友為了安全起見密碼設(shè)置的比較長,導致很多次密碼都輸入錯誤,嚴重影響了用戶體驗效果,下面通過本文給大家介紹Android程序開發(fā)之防止密碼輸入錯誤 密碼明文顯示功能,需要的朋友參考下2016-02-02