日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android-手势密码

發布時間:2024/1/8 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android-手势密码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引子

手勢密碼,移動開發中的常用功能點,看起來高大上,其實挺簡單的。

本文提供?我自定義的?手勢密碼控件布局,以及使用方法,首先附上github地址:https://github.com/18598925736/EazyGesturePwdLayoutDemo

?

實際效果動態圖

?

設置手勢密碼:

?

設置手勢密碼,當?前后兩次的手勢不一樣時

?

?

校驗手勢密碼-當5次都錯時:

?

校驗手勢密碼-當5次之內輸入正確時

?

重新設置手勢(之前設置過,現在需要修改手勢密碼)

?

源碼解析

首先說下開發思路:

上面的圖里面,我們主要看到了9個圓點,以及隨著手勢而產生的線條;

9個圓點,其實就是?自定義的View,如果你運行demo,把手放上去的畫,你會發現原點會出現圓環背景,這是在自定義的時候加上的功能,至于圓環的顏色寬度神馬的,你開心的話自己就行了。

至于線條,其實是?通過在一個自定義ViewGroup上重寫onToucheEvent監測?down,move和up來繪制的,9個圓點是被放置(用的 addView)在這個自定義ViewGroup里面,排布的方式看看源碼應該能明白;

特別說明一下這里有個坑:

在繪制線條的時候,我發現?我繪制出來的線條總是被9個圓點覆蓋,經過多方查詢,最終得出結論:這是ViewGroup的繪制機制導致的,它默認的繪制順序,是先繪制?background,然后是自己,然后是子,最后是裝飾;

看起來很抽象是吧?

看源碼;

最下方這個英語翻譯過來,就是我剛才說的意思,由于后繪制的會覆蓋先繪制的,所以,線條被子覆蓋也是正常的。

但是,這不是我想要的效果,問題是不是無解了呢?

也不是,只是大路不通,要走小路了;

還是看?View.java源碼:

?

發現,在繪制的第四步,DrawChildren中,調用的方法是dispatchDraw(canvas);?

那我如果在繪制子之后,再畫線,是不是可以讓線條覆蓋子。

所以,我重寫了這個方法,執行super.dispatchDraw()先保持原有邏輯,并且在執行我自己的繪制來畫線;

?

?OK,坑?解釋完畢。

自定義控件的源碼:

業內人士應該沒有什么看不懂的,畢竟我這個注釋已經是詳細得令人發指了(●′?`●)....

?

首先是那9個圓點:

1 package com.example.gesture_password_study.gesture_pwd.custom; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Canvas; 6 import android.graphics.Paint; 7 import android.support.annotation.Nullable; 8 import android.util.AttributeSet; 9 import android.view.View; 10 11 import com.example.gesture_password_study.R; 12 13 14 /** 15 * 手勢密碼專用的圓形控件 16 */ 17 public class GestureLockCircleView extends View { 18 19 public GestureLockCircleView(Context context) { 20 this(context, null); 21 } 22 23 public GestureLockCircleView(Context context, @Nullable AttributeSet attrs) { 24 this(context, attrs, 0); 25 } 26 27 public GestureLockCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 28 super(context, attrs, defStyleAttr); 29 dealAttr(context, attrs); 30 initPaint(); 31 } 32 33 private void dealAttr(Context context, AttributeSet attrs) { 34 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GestureLockCircleView); 35 36 if (ta != null) { 37 try { 38 circleFillColor = ta.getColor(R.styleable.GestureLockCircleView_gestureCircleFillColor, 0x00FE6665); 39 circleRadius = ta.getDimension(R.styleable.GestureLockCircleView_gestureCircleRadius, 0); 40 41 hasRoundBorder = ta.getBoolean(R.styleable.GestureLockCircleView_hasRoundBorder, false); 42 roundBorderColor = ta.getColor(R.styleable.GestureLockCircleView_roundBorderColor, 0x00FE6665); 43 roundBorderWidth = ta.getDimension(R.styleable.GestureLockCircleView_roundBorderWidth, 0); 44 } catch (Exception e) { 45 46 } finally { 47 ta.recycle(); 48 } 49 } 50 } 51 52 53 private int minWidth = 50, minHeight = 50; 54 55 /** 56 * 重寫onMeasure設定最小寬高 57 * 58 * @param widthMeasureSpec 59 * @param heightMeasureSpec 60 */ 61 @Override 62 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 63 setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); 64 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 65 int widthSize = MeasureSpec.getSize(widthMeasureSpec); 66 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 67 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 68 69 if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) { 70 setMeasuredDimension(minWidth, minHeight); 71 } else if (widthMode == MeasureSpec.AT_MOST) { 72 setMeasuredDimension(minWidth, heightSize); 73 } else if (heightMode == MeasureSpec.AT_MOST) { 74 setMeasuredDimension(widthSize, minHeight); 75 } 76 } 77 78 @Override 79 protected void onDraw(Canvas canvas) { 80 super.onDraw(canvas); 81 int width = getWidth(); 82 int height = getHeight(); 83 84 float centerX = width / 2; 85 float centerY = height / 2; 86 87 if (hasRoundBorder) { 88 canvas.drawCircle(centerX, centerY, roundBorderWidth, paint_border); 89 } 90 canvas.drawCircle(centerX, centerY, circleRadius, paint_inner); 91 92 } 93 94 private Paint paint_inner, paint_border; 95 96 97 private boolean hasRoundBorder; 98 private int roundBorderColor; 99 private float roundBorderWidth; 100 101 /** 102 * 設置內圈的顏色和半徑 103 * 104 * @param circleFillColor 105 * @param circleRadius 106 */ 107 public void setInnerCircle(int circleFillColor, float circleRadius) { 108 this.circleFillColor = circleFillColor; 109 this.circleRadius = circleRadius; 110 initPaint(); 111 postInvalidate(); 112 } 113 114 public void setBorderRound(boolean hasRoundBorder, int roundBorderColor, float roundBorderWidth) { 115 this.hasRoundBorder = hasRoundBorder; 116 this.roundBorderColor = roundBorderColor; 117 this.roundBorderWidth = roundBorderWidth; 118 initPaint(); 119 postInvalidate(); 120 } 121 122 123 private int circleFillColor; 124 private float circleRadius; 125 126 private void initPaint() { 127 paint_inner = new Paint(); 128 paint_inner.setColor(circleFillColor); 129 paint_inner.setAntiAlias(true);//抗鋸齒 130 paint_inner.setStyle(Paint.Style.FILL);//FILL填充,stroke描邊 131 132 paint_border = new Paint(); 133 paint_border.setColor(roundBorderColor); 134 paint_border.setAntiAlias(true);//抗鋸齒 135 paint_border.setStyle(Paint.Style.FILL);//FILL填充,stroke描邊 136 } 137 138 //3個狀態 139 public static final int STATUS_NOT_CHECKED = 0x01; 140 public static final int STATUS_CHECKED = 0x02; 141 public static final int STATUS_CHECKED_ERR = 0x03; 142 143 public void switchStatus(int status) { 144 switch (status) { 145 case STATUS_CHECKED: 146 circleFillColor = getResources().getColor(R.color.colorChecked); 147 roundBorderColor = getResources().getColor(R.color.colorRoundBorder); 148 break; 149 case STATUS_CHECKED_ERR: 150 circleFillColor = getResources().getColor(R.color.colorCheckedErr); 151 roundBorderColor = getResources().getColor(R.color.colorRoundBorderErr); 152 break; 153 case STATUS_NOT_CHECKED:// 普通狀態 154 default://以及缺省狀態 155 //沒有外框,內圈為灰色 156 circleFillColor = getResources().getColor(R.color.colorNotChecked); 157 roundBorderColor = getResources().getColor(R.color.transparent); 158 break; 159 } 160 initPaint(); 161 postInvalidate(); 162 } 163 164 }

?

然后是外層的布局:

1 package com.example.gesture_password_study.gesture_pwd.custom; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Canvas; 6 import android.graphics.Paint; 7 import android.graphics.Path; 8 import android.graphics.Point; 9 import android.graphics.Rect; 10 import android.util.AttributeSet; 11 import android.util.Log; 12 import android.view.MotionEvent; 13 import android.view.View; 14 import android.widget.RelativeLayout; 15 16 import com.example.gesture_password_study.R; 17 18 import java.util.ArrayList; 19 import java.util.List; 20 21 /** 22 * 手勢密碼繪制 控件; 23 */ 24 public class EasyGestureLockLayout extends RelativeLayout { 25 26 //全局變量統一管理 27 private Context mContext; 28 private boolean hasRoundBorder;//按鍵是否允許有圓環外圈 29 private boolean ifAllowInteract;//是否允許有事件交互 30 private Paint currentPaint;//當前使用的畫筆 31 private Paint paint_correct, paint_error;//畫線用的兩種顏色的畫筆 32 private GestureLockCircleView[] gestureCircleViewArr = null;//用數組來保存所有按鍵 33 private int mCount = 4;// 方陣的行數(列數等同) 34 private int mGesturePasswordViewWidth;//每一個按鍵的邊長(因為寬高相同) 35 private int mWidth, mHeight;//本layout的寬高 36 private int childStartIndex, childEndIndex;//畫軌跡線(密碼軌跡)的時候,需要指定子的起始和結束 index 37 private float marginRate = 0.2f;//縮小MotionEvent到達時的密碼鍵選中的判定范圍,這里的0.2的意思是,原本10*10的判定范圍,現在,縮小到6*6,其他4,被兩頭平分 38 private boolean ifAllowDrawLockPath = false;//因為有可能存在,down的時候沒有點在任何一個鍵位的范圍之內,所以必須用這個變量來控制是否進行繪制 39 private int guideLineStartX, guideLineStartY, guideLineEndX, guideLineEndY;//引導線(正在畫手勢,但是尚未或者無法形成軌跡線的時候,會出現)的起始和終止坐標 40 private int downX, downY;//MotionEvent的down事件坐標 41 private int movedX, movedY;//MotionEvent的move事件坐標 42 private Path lockPath = new Path();//密碼的圖形路徑.用于繪制軌跡線 43 private List<Integer> lockPathArr;//手勢密碼路徑,用于輸出到外界以及核對密碼 44 private int minLengthOfPwd = 4;//密碼最少位數 45 46 private int mModeStatus = -1; 47 private List<Integer> checkPwd;//外界傳入的需要核對的密碼 48 private int maxAttemptTimes = 5;//允許解鎖的最大嘗試次數,有必要的話,給他設置一個set方法,或者弄一個自定義屬性 49 private int currentAttemptTime = 1;// 當前嘗試次數 50 51 private int resetCurrentTime = 0;//當用戶重新設置密碼,這個值將會被重置 52 private List<Integer> tempPwd;//用于重新設置密碼 53 private boolean ifCheckOnErr = false;//當前是否檢測密碼曾失敗過 54 55 //常量 56 public static final int STATUS_RESET = 0x01;//本類狀態:重新設置,此狀態下會允許用戶繪制兩次手勢,而且必須相同,繪制完成之后,返回密碼值出去; 57 // 如果第二次繪制和第一次繪制不同,則強制重新繪制 58 public static final int STATUS_CHECK = 0x02;//本類狀態:校驗密碼,此狀態下,要求外界傳入密碼,然后給予用戶若干嘗試解鎖的次數, 59 // 如果規定次數之內,密碼相同,則返回解鎖成功; 60 // 如果規定次數之內,都沒有繪制出正確密碼,則返回解鎖失敗; 61 62 //************* 構造函數 ***************************** 63 public EasyGestureLockLayout(Context context) { 64 this(context, null); 65 } 66 67 public EasyGestureLockLayout(Context context, AttributeSet attrs) { 68 this(context, attrs, 0); 69 } 70 71 public EasyGestureLockLayout(Context context, AttributeSet attrs, int defStyleAttr) { 72 super(context, attrs, defStyleAttr); 73 dealAttr(context, attrs); 74 init(context); 75 } 76 77 //************* 屬性值獲取 ***************************** 78 private void dealAttr(Context context, AttributeSet attrs) { 79 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.EasyGestureLockLayout); 80 81 if (ta != null) { 82 try { 83 hasRoundBorder = ta.getBoolean(R.styleable.EasyGestureLockLayout_ifChildHasBorder, false); 84 mCount = ta.getInteger(R.styleable.EasyGestureLockLayout_count, 3); 85 86 ifAllowInteract = ta.getBoolean(R.styleable.EasyGestureLockLayout_ifAllowInteract, false); 87 } catch (Exception e) { 88 89 } finally { 90 ta.recycle(); 91 } 92 } 93 } 94 95 //************* 重寫方法 ***************************** 96 @Override 97 protected void onMeasure(int widthSpec, int heightSpec) { 98 super.onMeasure(widthSpec, heightSpec); 99 100 //取測量之后的寬和高 101 mWidth = MeasureSpec.getSize(widthSpec); 102 mHeight = MeasureSpec.getSize(heightSpec); 103 //強行將繪圖使用的寬高置為 測量寬高中的較小值, 因為繪圖不能超出邊界 104 mHeight = mWidth = mWidth < mHeight ? mWidth : mHeight; 105 106 // 初始化mGestureLockViews 107 if (gestureCircleViewArr == null) { 108 gestureCircleViewArr = new GestureLockCircleView[mCount * mCount];//用數組來保存 “按鍵” 109 mGesturePasswordViewWidth = mWidth / mCount;//等分,不需要留間隙, 因為圓形控件會自己留空隙 110 111 //利用相對布局的參數來放置子元素 112 for (int i = 0; i < gestureCircleViewArr.length; i++) { 113 //初始化每個GestureLockView 114 gestureCircleViewArr[i] = getCircleView(mHeight); 115 gestureCircleViewArr[i].setId(i + 1); 116 LayoutParams lockerParams = new LayoutParams( 117 mGesturePasswordViewWidth, mGesturePasswordViewWidth); 118 119 // 不是每行的第一個,則設置位置為前一個的右邊 120 if (i % mCount != 0) { 121 lockerParams.addRule(RelativeLayout.RIGHT_OF, 122 gestureCircleViewArr[i - 1].getId()); 123 } 124 // 從第二行開始,設置為上一行同一位置View的下面 125 if (i > mCount - 1) { 126 lockerParams.addRule(RelativeLayout.BELOW, 127 gestureCircleViewArr[i - mCount].getId()); 128 } 129 lockerParams.setMargins(0, 0, 0, 0); 130 addView(gestureCircleViewArr[i], lockerParams); 131 } 132 } 133 134 } 135 136 /** 137 * 實驗結果,在這里onDraw,繪制出來的線,總是會被子元素覆蓋, 138 * 139 * @param canvas 140 */ 141 @Override 142 protected void onDraw(Canvas canvas) { //鬧半天,這個onDraw沒有執行 143 super.onDraw(canvas); 144 //奇怪,為何不執行onDraw 145 // 一般情況下,viewGroup都不會執行onDraw,因為它本身是一個容器,容器不具有自我繪制功能; 146 //圖像的表現,和繪制的順序有關系; 147 Log.d("onDrawTag", "onDraw"); 148 } 149 150 /** 151 * 然而,由這個方法進行繪制,線,則會覆蓋"子"; 152 * 153 * @param canvas 154 */ 155 @Override 156 public void dispatchDraw(Canvas canvas) { 157 super.dispatchDraw(canvas);//這一步居然就是繪制 “子”, 具體看View.java 的 19195行 158 Log.d("onDrawTag", "dispatchDraw");//那么, 等children畫完了之后,再畫線,就名正言順了。⊙︿⊙ 一頭包。明白了 159 if (gestureCircleViewArr != null && ifAllowInteract) { 160 drawLockPath(canvas); 161 drawMovingPath(canvas); 162 } 163 } 164 165 //************* 模式設置 ***************************** 166 167 public int getCurrentMode() { 168 return mModeStatus; 169 } 170 171 /** 172 * 切換到Reset模式,重新設置手勢密碼; 173 * 此模式下,不需要入參。設置完成之后,會執行回調GestureEventCallback.onResetFinish(pwd); 174 */ 175 public void switchToResetMode() { 176 mModeStatus = STATUS_RESET; 177 } 178 179 /** 180 * 切換到 校驗模式; 181 * 這個模式需要傳入原始密碼,以及最大嘗試的次數; 182 * <p> 183 * 嘗試解鎖成功,或者超過了最大嘗試次數都沒有成功,就會執行回調GestureEventCallback.onCheckFinish(boolean succeedOrFailed); 184 * 185 * @param pwd 186 * @param maxAttemptTimes 187 */ 188 public void switchToCheckMode(List<Integer> pwd, int maxAttemptTimes) { 189 if (pwd == null || maxAttemptTimes <= 0) { 190 Log.e("switchToCheckMode", "參數錯誤,pwd不能為空,而且 maxAttemptTimes必須大于0"); 191 return; 192 } 193 this.currentAttemptTime = 1; 194 this.mModeStatus = STATUS_CHECK; 195 this.maxAttemptTimes = maxAttemptTimes; 196 this.checkPwd = copyPwd(pwd); 197 } 198 199 //****************************以下全是業務代碼************************** 200 private int background_color = 0xff4790FF; 201 private int background_color_transparent = 0x00000000; 202 203 /** 204 * 初始化畫筆, 205 * 206 * @param context 207 */ 208 private void init(Context context) { 209 mContext = context; 210 setClickable(true);//為了順利接收事件,需要開啟click;因為你如果不設置,,就只能收到down,其他的一概收不到 211 setBackgroundColor(background_color_transparent);//設置透明色;這里如果不設置,onDraw將不會執行;原因:這是一個ViewGroup,本身是容器,不具備自我繪制功能,但是這里設置了背景色,就說明有東西需要繪制,onDraw就會執行; 212 213 paint_correct = new Paint(); 214 paint_correct.setStyle(Paint.Style.STROKE); 215 paint_correct.setAntiAlias(true); 216 paint_correct.setColor(getResources().getColor(R.color.colorChecked)); 217 218 paint_error = new Paint(); 219 paint_error.setStyle(Paint.Style.STROKE); 220 paint_error.setAntiAlias(true); 221 paint_error.setColor(getResources().getColor(R.color.colorCheckedErr)); 222 223 initLockPathArr(); 224 currentPaint = paint_correct;// 默認使用的畫筆 225 } 226 227 /** 228 * 構建單個圓 229 * 230 * @param wh 邊長 231 * @return 232 */ 233 private GestureLockCircleView getCircleView(int wh) { 234 GestureLockCircleView gestureCircleView = new GestureLockCircleView(mContext); 235 236 double s = Math.pow(mCount, 3) + 0.5f;//除法系數,用于計算內圓的半徑; 行數的3次方,并且轉為浮點型 237 gestureCircleView.setInnerCircle(getResources().getColor(R.color.colorChecked), (float) (wh / s)); 238 239 paint_correct.setStrokeWidth((float) (wh / s) * 0.2f); 240 paint_error.setStrokeWidth((float) (wh / s) * 0.2f); 241 242 //內圓顏色,內圓半徑 243 s = Math.pow(mCount, 2) + 0.5f;//除法系數,用于計算外圓的半徑;行數的2次方,并且轉為浮點型 244 gestureCircleView.setBorderRound(hasRoundBorder, getResources().getColor(R.color.colorChecked), (float) (wh / s));//是否有邊框,外圓顏色,外圓半徑 245 gestureCircleView.switchStatus(GestureLockCircleView.STATUS_NOT_CHECKED); 246 return gestureCircleView; 247 } 248 249 /** 250 * 重置所有按鍵為 notChecked 狀態 251 */ 252 private void resetAllCircleBtn() { 253 if (gestureCircleViewArr == null) return; 254 for (int i = 0; i < gestureCircleViewArr.length; i++) { 255 gestureCircleViewArr[i].switchStatus(GestureLockCircleView.STATUS_NOT_CHECKED); 256 } 257 } 258 259 //*************************手勢密碼路徑的管理*********************************************** 260 private void initLockPathArr() { 261 lockPathArr = new ArrayList<>(); 262 } 263 264 /** 265 * 增加一個密碼數字 266 * 267 * @param p 268 */ 269 private void addPwd(int p) { 270 if (!checkRepetition(p)) { 271 lockPathArr.add(p); 272 } 273 } 274 275 private void resetPwd() { 276 if (lockPathArr == null) 277 lockPathArr = new ArrayList<>(); 278 else 279 lockPathArr.clear(); 280 } 281 282 /** 283 * 繪制密碼“軌跡線” 284 * 285 * @param canvas 286 */ 287 private void drawLockPath(Canvas canvas) { 288 canvas.drawPath(lockPath, currentPaint); 289 } 290 291 /** 292 * 重置引導線的起/終 坐標值 293 */ 294 private void resetMovingPathCoordinate() { 295 guideLineStartX = 0; 296 guideLineStartY = 0; 297 guideLineEndX = 0; 298 guideLineEndY = 0; 299 } 300 301 /** 302 * 繪制引導線 303 */ 304 private void drawMovingPath(Canvas canvas) { 305 if (guideLineStartX != 0 && guideLineStartY != 0)//只有當起始位置不是0的時候,才進行繪制 306 canvas.drawLine(guideLineStartX, guideLineStartY, guideLineEndX, guideLineEndY, currentPaint); 307 } 308 309 /** 310 * 輔助方法,獲得一個View的中心位置 311 * 312 * @param v 313 * @return 314 */ 315 private Point getCenterPoint(View v) { 316 Rect rect = new Rect(); 317 v.getHitRect(rect); 318 int x = rect.left + v.getWidth() / 2; 319 int y = rect.top + v.getHeight() / 2; 320 return new Point(x, y); 321 } 322 323 /** 324 * 判斷當前點擊的點位置是不是在子元素范圍之內 325 * 326 * @param x 327 * @param y 328 * @param v 329 * @return 330 */ 331 private boolean ifClickOnView(int x, int y, View v) { 332 Rect r = new Rect(); 333 v.getHitRect(r); 334 335 //判定點是不是在view范圍內,根據業務需求,要給view一個判定的間隙,比如 5*5的View,判定范圍只能是3*3 336 //以原來的矩陣為基礎,重新定一個判定范圍,范圍暫時定位原來的80% 337 //真正的判定區域的矩陣范圍 338 339 int w = v.getWidth(); 340 int h = v.getHeight(); 341 342 int realLeft = (int) (r.left + marginRate * w); 343 int realTop = (int) (r.top + marginRate * h); 344 int realRight = (int) (r.right - marginRate * w); 345 int realBottom = (int) (r.bottom - marginRate * h); 346 347 Rect rect1 = new Rect(realLeft, realTop, realRight, realBottom); 348 349 if (rect1.contains(x, y)) { 350 return true; 351 } 352 return false; 353 } 354 355 /** 356 * 根據點坐標,返回當前點在哪個密碼鍵的范圍內,直接返回View對象 357 * 358 * @param x 359 * @param y 360 * @return 361 */ 362 private GestureLockCircleView getClickedChild(int x, int y) { 363 for (GestureLockCircleView v : gestureCircleViewArr) { 364 if (ifClickOnView(x, y, v)) {// 365 return v; 366 } 367 } 368 return null; 369 } 370 371 /** 372 * 根據點坐標,返回當前點在哪個密碼鍵的范圍內,直接返回View對象的id 373 * 374 * @param x 375 * @param y 376 * @return 377 */ 378 private int getClickedChildIndex(int x, int y) { 379 for (int i = 0; i < gestureCircleViewArr.length; i++) { 380 View v = gestureCircleViewArr[i]; 381 if (ifClickOnView(x, y, v)) {// 382 return i; 383 } 384 } 385 return -1; 386 } 387 388 /** 389 * 檢查密碼值是否重復 390 * 391 * @return 392 */ 393 private boolean checkRepetition(int pwd) { 394 return lockPathArr.contains(pwd); 395 } 396 397 /** 398 * 手勢繪制 399 * 400 * @param event 401 * @return 402 */ 403 @Override 404 public boolean onTouchEvent(MotionEvent event) { 405 if (ifAllowInteract)//只有設置了允許事件交互,才往下執行 406 switch (event.getAction()) { 407 case MotionEvent.ACTION_DOWN: 408 onToast("", ColorHolder.COLOR_GRAY); 409 downX = (int) event.getX(); 410 downY = (int) event.getY(); 411 ifAllowDrawLockPath = false; 412 GestureLockCircleView current = getClickedChild(downX, downY); 413 if (current != null) {//如果當前按下的點,沒有在任何一個按鍵范圍之內 414 ifAllowDrawLockPath = true; 415 416 if (ifCheckOnErr) 417 current.switchStatus(GestureLockCircleView.STATUS_CHECKED_ERR); 418 else 419 current.switchStatus(GestureLockCircleView.STATUS_CHECKED);//down的時候,將當前這個按鍵設置為checked 420 421 childStartIndex = getClickedChildIndex(downX, downY); 422 //記錄手勢密碼 423 lockPath.reset(); 424 resetPwd(); 425 addPwd(childStartIndex); 426 //path處理 427 Point startP = getCenterPoint(gestureCircleViewArr[childStartIndex]); 428 if (startP != null) {//因為如果 429 lockPath.moveTo(startP.x, startP.y); 430 //引導線的起始坐標 431 guideLineStartX = startP.x; 432 guideLineStartY = startP.y; 433 } else { 434 Log.d("tagpx", "1"); 435 } 436 } else { 437 //如果第一次點下去,就是在 鍵位的空隙里面。那么,就不用繪制了 438 Log.d("tagpx", "2"); 439 } 440 441 break; 442 case MotionEvent.ACTION_MOVE: 443 if (ifAllowDrawLockPath) { 444 movedX = (int) event.getX(); 445 movedY = (int) event.getY(); 446 childEndIndex = getClickedChildIndex(movedX, movedY); 447 448 //-1表示沒有找到對應的區域 449 boolean flag1 = childStartIndex != -1 && childEndIndex != -1;//沒有獲取到正確的對應區域 450 boolean flag2 = childStartIndex != childEndIndex;//在同一個區域內不需要畫線 451 boolean flag3 = checkRepetition(childEndIndex);//不允許密碼值重復,這里要檢查當前這個區域是不是已經在lockPathArr里面 452 453 if (flag1 && flag2 && !flag3) {//如果起點終點都在區域之內,那么就直接繪制“軌跡線” 454 Point endP = getCenterPoint(gestureCircleViewArr[childEndIndex]); 455 GestureLockCircleView cur = getClickedChild(movedX, movedY); 456 if (ifCheckOnErr) 457 cur.switchStatus(GestureLockCircleView.STATUS_CHECKED_ERR); 458 else 459 cur.switchStatus(GestureLockCircleView.STATUS_CHECKED); 460 461 addPwd(childEndIndex); 462 lockPath.lineTo(endP.x, endP.y); 463 464 guideLineStartX = endP.x; 465 guideLineStartY = endP.y; 466 } 467 guideLineEndX = movedX; 468 guideLineEndY = movedY; 469 postInvalidate();//刷新視圖 470 } 471 break; 472 case MotionEvent.ACTION_UP: 473 case MotionEvent.ACTION_CANCEL: 474 if (ifAllowDrawLockPath) { 475 resetMovingPathCoordinate(); // up的時候,要清除引導線 476 lockPath.reset(); //同時要清除軌跡線 477 postInvalidate();//刷新本layout 478 resetAllCircleBtn();//up的時候,把所有按鍵全部設置為notChecked, 479 onSwipeFinish(); 480 if (lockPathArr.size() >= minLengthOfPwd) { 481 if (mModeStatus == STATUS_RESET) {//如果處于reset模式下,執行rest的回調 482 onReset(); 483 } else if (mModeStatus == STATUS_CHECK) {//檢查模式下,執行onCheck 484 onCheck(); 485 } else { 486 throw new RuntimeException("異常模式,請正確調用switchToCheckMode/switchToResetMode!"); 487 } 488 } else { 489 onToast(String.format(ToastStrHolder.swipeTooLittlePointStr, minLengthOfPwd), ColorHolder.COLOR_RED); 490 } 491 } 492 break; 493 default: 494 break; 495 } 496 return super.onTouchEvent(event); 497 } 498 499 private void onSwipeFinish() { 500 if (mGestureEventCallback == null) return; 501 mGestureEventCallback.onSwipeFinish(copyPwd(lockPathArr)); 502 } 503 504 private void onReset() { 505 if (mGestureEventCallback == null) return; 506 if (resetCurrentTime == 0) {//第一次繪制,賦值給tempPwd 507 tempPwd = copyPwd(lockPathArr); 508 resetCurrentTime++; 509 onToast(ToastStrHolder.tryAgainStr, ColorHolder.COLOR_GRAY); 510 } else { 511 try { 512 boolean s = compare(tempPwd, lockPathArr); 513 if (s) { 514 onToast(ToastStrHolder.successStr, ColorHolder.COLOR_GRAY); 515 mGestureEventCallback.onResetFinish(copyPwd(lockPathArr));//執行回調 516 } else { 517 onToast(ToastStrHolder.notSameStr, ColorHolder.COLOR_RED); 518 } 519 } catch (RuntimeException e) { 520 e.printStackTrace(); 521 } 522 } 523 } 524 525 /** 526 * 初始化當前的繪制次數 527 */ 528 public void initCurrentTimes() { 529 resetCurrentTime = 0; 530 } 531 532 private void onCheck() { 533 if (mGestureEventCallback == null) return; 534 boolean compareRes = compare(checkPwd, lockPathArr); //對比當前密碼和外界傳入的密碼 535 if (currentAttemptTime <= maxAttemptTimes) {//如果還能繼續嘗試解鎖,那么 536 if (compareRes) {//如果成功 537 mGestureEventCallback.onCheckFinish(compareRes);//直接返回結果 538 539 currentAttemptTime = 1; 540 currentPaint = paint_correct; 541 ifCheckOnErr = false; 542 } else {//否則,提示 543 int remindTime = maxAttemptTimes - currentAttemptTime; 544 if (remindTime > 0) { 545 onToast(String.format(ToastStrHolder.wrongPwdInputStr, remindTime), ColorHolder.COLOR_RED); 546 547 currentPaint = paint_error; 548 ifCheckOnErr = true; 549 } else { 550 mGestureEventCallback.onCheckFinish(compareRes);//直接返回結果 551 } 552 currentAttemptTime++; 553 } 554 } else {//如果已經不能嘗試, 無論是否成功,都要返回結果 555 mGestureEventCallback.onCheckFinish(compareRes); 556 currentAttemptTime = 1; 557 } 558 } 559 560 private void onSwipeMore() { 561 if (mGestureEventCallback == null) return; 562 mGestureEventCallback.onSwipeMore(); 563 } 564 565 private void onToast(String s, int color) { 566 if (mGestureEventCallback == null) return; 567 mGestureEventCallback.onToast(s, color); 568 } 569 570 /** 571 * 提供一個方法,繪制密碼點,但是只繪制 圓圈,不繪制引導線和軌跡線 572 */ 573 public void refreshPwdKeyboard(List<Integer> pwd) { 574 try { 575 for (int i = 0; i < mCount * mCount; i++) {//先把所有的點都設置為notChecked 576 gestureCircleViewArr[i].switchStatus(GestureLockCircleView.STATUS_NOT_CHECKED); 577 } 578 579 if (null != pwd) 580 for (int i = 0; i < pwd.size(); i++) {//再把密碼中的點,設置為checked 581 gestureCircleViewArr[pwd.get(i)].switchStatus(GestureLockCircleView.STATUS_CHECKED); 582 } 583 } catch (IndexOutOfBoundsException e) { 584 //這里有可能發生數組越界,因為 本類的各個對象時相互獨立的,方陣行數可能不同 585 e.printStackTrace(); 586 } 587 } 588 589 //*************************下面業務對接*********************************************** 590 public interface GestureEventCallback { 591 /** 592 * 當滑動結束,無論模式,只要滑動之后發現upEvent就執行 593 */ 594 void onSwipeFinish(List<Integer> pwd); 595 596 /** 597 * 當重新設置密碼成功的時候,將密碼返回出去 598 * 599 * @param pwd 設置的密碼 600 */ 601 void onResetFinish(List<Integer> pwd); 602 603 /** 604 * 如果當前模式是 check模式,則用這個方法來返回check的結果 605 * 606 * @param succeedOrFailed 校驗是否成功 607 */ 608 void onCheckFinish(boolean succeedOrFailed); 609 610 /** 611 * 如果當前滑動的密碼格子數太少(比如設置了至少滑動4格,卻只滑了2格) 612 */ 613 void onSwipeMore(); 614 615 /** 616 * 當需要給外界反饋信息的時候 617 * 618 * @param s 信息內容 619 * @param color 有必要的話,傳字體顏色給外界 620 */ 621 void onToast(String s, int color); 622 } 623 624 /** 625 * 反饋給外界的回調 626 */ 627 private GestureEventCallback mGestureEventCallback; 628 629 public void setGestureFinishedCallback(GestureEventCallback gestureFinishedCallback) { 630 this.mGestureEventCallback = gestureFinishedCallback; 631 } 632 633 public static class GestureEventCallbackAdapter implements GestureEventCallback { 634 635 @Override 636 public void onSwipeFinish(List<Integer> pwd) { 637 638 } 639 640 @Override 641 public void onResetFinish(List<Integer> pwd) { 642 643 } 644 645 @Override 646 public void onCheckFinish(boolean succeedOrFailed) { 647 648 } 649 650 @Override 651 public void onSwipeMore() { 652 653 } 654 655 @Override 656 public void onToast(String s, int color) { 657 658 } 659 } 660 661 //*************************下面是輔助方法以及輔助內部類*********************************************** 662 663 /** 664 * 輔助方法,復制一份密碼對象,因為如果直接把當前對象的密碼返回出去,則外界使用的全部都是同一個對象,這個對象可能隨時變化,外層邏輯無法對比密碼值 665 */ 666 private List<Integer> copyPwd(List<Integer> pwd) { 667 List<Integer> copyOne = new ArrayList<>(); 668 for (int i = 0; i < pwd.size(); i++) { 669 copyOne.add(pwd.get(i)); 670 } 671 return copyOne; 672 } 673 674 /** 675 * 對比兩個list是否內容完全相同 676 */ 677 private boolean compare(List<Integer> list1, List<Integer> list2) throws RuntimeException { 678 679 if (list1 == null || list2 == null) { 680 throw new RuntimeException("存在list為空,不執行對比"); 681 } 682 683 if (list1.size() != list2.size())//size長度都不同,就不用比了 684 return false; 685 686 for (int i = 0; i < list1.size(); i++) { 687 if (list1.get(i) != list2.get(i)) { 688 return false; 689 } 690 } 691 return true; 692 } 693 694 695 public class ColorHolder { 696 public static final int COLOR_RED = 0xffFF3232; 697 public static final int COLOR_GRAY = 0xff999999; 698 public static final int COLOR_YELLOW = 0xffF8A916; 699 } 700 701 public class ToastStrHolder { 702 public static final String successStr = "繪制成功"; 703 public static final String tryAgainStr = "請再次繪制手勢密碼"; 704 public static final String notSameStr = "與首次繪制不一致,請再次繪制"; 705 public static final String forYourSafetyStr = "為了您的賬戶安全,請設置手勢密碼"; 706 public static final String swipeTooLittlePointStr = "請最少連接%s個點"; 707 public static final String wrongPwdInputStr = "輸入錯誤,您還可以輸入%s次"; 708 } 709 }

?

?

?具體使用方法:


只展示一個例子,這是設置手勢密碼的界面,紅色的代碼就是你需要自己編寫的;

package com.example.gesture_password_study.gesture_pwd;import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import android.widget.TextView; import android.widget.Toast;import com.example.gesture_password_study.R; import com.example.gesture_password_study.gesture_pwd.base.GestureBaseActivity; import com.example.gesture_password_study.gesture_pwd.custom.EasyGestureLockLayout;import java.util.List;/*** 手勢密碼 設置界面*/ public class GesturePwdSettingActivity extends GestureBaseActivity {EasyGestureLockLayout layout_small;TextView tv_go;TextView tv_redraw;EasyGestureLockLayout layout_parent;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.layout_gesture_pwd_setting);initView();initLayoutView();}private void initView() {tv_go = findViewById(R.id.tv_go);layout_parent = findViewById(R.id.layout_parent);layout_small = findViewById(R.id.layout_small);tv_redraw = findViewById(R.id.tv_redraw);}protected void initLayoutView() {//寫個適配器EasyGestureLockLayout.GestureEventCallbackAdapter adapter = new EasyGestureLockLayout.GestureEventCallbackAdapter() {@Overridepublic void onSwipeFinish(List<Integer> pwd) {layout_small.refreshPwdKeyboard(pwd);//通知另一個小密碼盤,將密碼點展示出來,但是不展示軌跡線tv_redraw.setVisibility(View.VISIBLE);}@Overridepublic void onResetFinish(List<Integer> pwd) {// 當密碼設置完成savePwd(showPwd("showGesturePwdInt", pwd));//保存密碼到本地Toast.makeText(GesturePwdSettingActivity.this, "密碼已保存", Toast.LENGTH_SHORT).show();}@Overridepublic void onCheckFinish(boolean succeedOrFailed) {String str = succeedOrFailed ? "解鎖成功" : "解鎖失敗";Toast.makeText(GesturePwdSettingActivity.this, str, Toast.LENGTH_SHORT).show();if (succeedOrFailed) {//如果解鎖成功,則切換到set模式layout_parent.switchToResetMode();} else {onCheckFailed();}}@Overridepublic void onSwipeMore() {//執行動畫animate(tv_go);}@Overridepublic void onToast(String s, int textColor) {tv_go.setText(s);if (textColor != 0)tv_go.setTextColor(textColor);if (textColor == 0xffFF3232) {animate(tv_go);}}};layout_parent.setGestureFinishedCallback(adapter);//使用rest模式layout_parent.switchToResetMode();tv_redraw.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {layout_parent.initCurrentTimes();tv_redraw.setVisibility(View.INVISIBLE);layout_small.refreshPwdKeyboard(null);tv_go.setText("請重新繪制");}});}}

?

它的布局xml:

layout_gesture_pwd_setting.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"android:gravity="center_horizontal"android:orientation="vertical"><TextViewandroid:id="@+id/tv_skip"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:layout_marginBottom="16dp"android:layout_marginRight="20dp"android:layout_marginTop="40dp"android:text="--"android:textColor="@color/color_v"android:textSize="15sp" /><com.example.gesture_password_study.gesture_pwd.custom.EasyGestureLockLayoutandroid:id="@+id/layout_small"android:layout_width="@dimen/small_grid_width"android:layout_height="@dimen/small_grid_width"app:count="3"app:ifAllowInteract="false"app:ifChildHasBorder="false" /><TextViewandroid:id="@+id/tv_go"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="24dp"android:text="為了您的賬戶安全,請設置手勢密碼"android:textColor="#F8A916"android:textSize="13sp" /><com.example.gesture_password_study.gesture_pwd.custom.EasyGestureLockLayoutandroid:id="@+id/layout_parent"android:layout_width="@dimen/big_grid_width"android:layout_height="@dimen/big_grid_width"android:layout_marginTop="64dp"app:count="3"app:ifAllowInteract="true"app:ifChildHasBorder="true" /><TextViewandroid:id="@+id/tv_redraw"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="重新繪制"android:textColor="@color/color_v"android:textSize="15sp"android:visibility="invisible"/></LinearLayout>

count屬性,是控制?密碼盤的?方陣寬度,目前是3,所以呈現出來就是3*3;

你可以換成4,5,6···隨意,只要你沒有密集恐懼癥.```````````

?

?===========================================

?歐拉,源碼解讀就到這里,也沒什么復雜的東西。

想起之前面試的時候有一個大佬問我的問題,?自定義ViewGroup能不能在里面同時放置子View并且還能對自身進行繪制。

當時一臉懵逼,不知道什么意思,····?現在知道了。

自定義ViewGroup,然后addView。。。然后還?onDraw··自己。

?

?

?

喜歡的大佬可以下載源碼,歡迎留言討論···

轉載于:https://www.cnblogs.com/hankzhouAndroid/p/9590583.html

總結

以上是生活随笔為你收集整理的android-手势密码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲精品中文在线资源 | 在线亚洲人成电影网站色www | 91麻豆精品国产91久久久无需广告 | www.888.av| 少妇搡bbbb搡bbb搡69 | 日韩精品首页 | 在线观看视频色 | 久久电影国产免费久久电影 | 久久黄色免费 | 最近中文字幕视频完整版 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 中文字幕高清在线 | 久久久黄色免费网站 | 国产区在线看 | 在线视频a| 亚州国产精品久久久 | 日韩欧美综合在线视频 | 色婷婷国产精品 | 伊人久久精品久久亚洲一区 | 中文字幕丝袜一区二区 | 1区2区视频 | 中文字幕丝袜制服 | 欧美福利片在线观看 | 国产亚洲欧美日韩高清 | 国产少妇在线观看 | 九九九在线观看视频 | 久久综合久久综合九色 | 狠狠搞,com | 亚洲免费av片 | 亚洲激色 | 亚洲丝袜中文 | 伊人久久av| 亚洲黄色免费在线看 | 色综合国产| 亚洲在线视频观看 | 欧美日韩国产精品一区二区三区 | 中文字幕一区二区三区在线观看 | 在线观看色网站 | www四虎影院 | 免费看黄在线 | 美女国产精品 | 亚洲精品看片 | 国产黄色a | 国产一区视频免费在线观看 | 91亚洲狠狠婷婷综合久久久 | 精品国产乱码久久久久久三级人 | 中文一二区 | 天天干天天操天天入 | 91精品国 | 黄色网中文字幕 | 欧美激情综合网 | 久草在线免费资源 | 中文字幕在线免费看线人 | 日韩欧美视频免费在线观看 | 91av视频 | 午夜电影 电影 | 色综合网在线 | 免费日韩av片 | 久久久久久精 | 丁香六月网 | www免费看| 成人av影视在线 | 在线观看免费成人 | 欧美黑人性猛交 | 亚洲开心激情 | 97精品国产aⅴ | 精品一区二区三区电影 | 免费黄色在线 | 香蕉视频国产在线观看 | 久久久久久久久久久福利 | 97超碰中文字幕 | 国产高清一区二区 | 91中文字幕视频 | 久久久99精品免费观看 | 美女一区网站 | 欧美激情一区不卡 | 亚洲最新精品 | 婷婷网站天天婷婷网站 | 夜夜爱av| 五月激情av| 日韩美一区二区三区 | 这里只有精彩视频 | 国产91影院 | av网在线观看| 夜夜骑首页 | 成年人免费看 | 久久精品男人的天堂 | www.一区二区三区 | 亚洲国产操 | 91精品久久香蕉国产线看观看 | 日韩电影久久 | 中字幕视频在线永久在线观看免费 | 午夜av电影院 | 最新国产精品拍自在线播放 | 国产专区视频在线观看 | 国产糖心vlog在线观看 | 免费亚洲黄色 | 日韩r级在线| 国产精品人人做人人爽人人添 | 精品一区91| 狠狠色综合网站久久久久久久 | 九九欧美| 91香蕉视频色版 | 免费看一级特黄a大片 | 国产精品久久久久四虎 | 狠狠88综合久久久久综合网 | 日本爱爱片 | 中文不卡视频 | 99爱爱| 人人躁| 人人玩人人添人人澡超碰 | 精品视频区 | 亚洲欧美成人在线 | 最近高清中文在线字幕在线观看 | 91精品久久久久久粉嫩 | 国产午夜精品视频 | 亚洲 综合 国产 精品 | 久久久久这里只有精品 | 亚洲另类在线视频 | 亚洲另类人人澡 | 久久国产精品一区二区三区 | 成人久久18免费网站 | 欧美一级免费高清 | 国产v在线 | 综合五月 | 超碰人人舔 | 在线视频一区观看 | 九九热精 | 中文字幕成人在线观看 | 精品91久久久久 | 夜夜夜精品 | 日日夜夜国产 | 在线观看视频在线观看 | 九九爱免费视频在线观看 | 五月婷激情 | 91九色成人 | 国产日韩视频在线播放 | 国产在线精品一区二区三区 | 欧洲精品二区 | 久久最新 | 免费网站黄 | 91在线日韩 | 亚洲波多野结衣 | 日韩电影在线观看一区二区 | 九九导航| 91片黄在线观看 | 久久视频在线观看免费 | 免费久久网 | 亚洲婷婷综合色高清在线 | 一区二区视频在线看 | 国产很黄很色的视频 | 午夜精品久久久久久久99水蜜桃 | 久久国产精品久久国产精品 | 精品综合久久 | 婷婷在线播放 | 黄色成年网站 | 久艹视频在线免费观看 | 久久精品牌麻豆国产大山 | 西西www4444大胆在线 | 欧美日韩综合在线 | 天堂在线成人 | 色婷av| av三级在线播放 | 亚洲欧美在线综合 | av电影在线免费观看 | 激情综合网五月激情 | 国产999精品久久久影片官网 | 99热在线国产 | 中文字幕国产视频 | 欧美成人精品欧美一级乱黄 | 日韩最新av在线 | 久久中文字幕视频 | 日本黄色一级电影 | 久久久久久久久艹 | 亚洲香蕉在线观看 | 黄色软件在线观看 | 国产在线视频导航 | 97高清视频 | 在线看国产精品 | 免费网址你懂的 | 精品视频中文字幕 | 99在线视频播放 | 精品欧美乱码久久久久久 | www.天天操 | 99在线看| 欧美性受极品xxxx喷水 | 三级黄色a| 亚洲精品国产第一综合99久久 | 正在播放国产精品 | 日韩极品在线 | 国产美女精品视频 | 国产视频在线观看免费 | 国产专区视频在线 | 久久久私人影院 | 久艹视频免费观看 | 97av影院| 91福利免费 | 日韩精品一区二区免费 | 激情文学综合丁香 | 天天综合久久 | 国产成人精品av在线观 | 在线成人一区二区 | 福利一区视频 | 国产视频一区二区在线播放 | 亚洲小视频在线 | 日韩亚洲在线视频 | 超碰97在线资源站 | 9在线观看免费高清完整版 玖玖爱免费视频 | 久久99精品国产91久久来源 | 日韩在线一区二区免费 | 久久精品视频免费观看 | 免费在线观看av网站 | 中文字幕免费高清在线 | 一级a性色生活片久久毛片波多野 | 精品一区二区免费在线观看 | 丁香婷婷激情网 | 99riav1国产精品视频 | 国产97色在线 | 日韩在线电影一区 | 亚洲第一香蕉视频 | 福利区在线观看 | 国产免费小视频 | 在线观看日韩免费视频 | 国产成人在线观看 | 超碰97人| 啪啪凸凸 | 黄色影院在线免费观看 | 在线观看完整版免费 | 成人一级片免费看 | 久久精品首页 | 欧美国产日韩一区二区三区 | 国产一区二区三区四区大秀 | 国产夫妻性生活自拍 | 一二区av | 国产自偷自拍 | 免费福利在线观看 | a资源在线 | 成人高清av在线 | 成人久久久电影 | 另类五月激情 | 一区二区三区播放 | 日韩欧美视频在线播放 | 国产超碰在线观看 | 亚洲一级片在线观看 | 日韩有码欧美 | 日韩黄色在线观看 | 欧美精品久久人人躁人人爽 | 久久免费视频网站 | 欧美婷婷色 | 91麻豆精品国产91久久久无需广告 | 午夜三级在线 | 青草视频网 | av片在线观看免费 | 国产午夜麻豆影院在线观看 | 一区二区三区免费在线观看视频 | 成人免费视频在线观看 | 97超碰.com| www黄com | 高潮久久久久久 | 亚洲九九爱 | 欧美a级在线播放 | 久久av影院| 人人干人人添 | 国产 成人 久久 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 天天激情天天干 | 日日夜夜综合 | 国产精品3 | 久久久久www | 天天天干天天射天天天操 | 香蕉影视在线观看 | 99中文字幕视频 | 玖玖精品在线 | 国产欧美精品一区二区三区四区 | 久久99亚洲精品久久 | 香蕉影视app | 在线观看中文字幕一区二区 | 天天爱天天 | 97色在线观看免费视频 | 精品中文字幕在线观看 | 色婷婷激情综合 | 六月色| 免费av网址在线观看 | 激情视频在线观看网址 | 热久久视久久精品18亚洲精品 | 国产一区免费视频 | 伊人午夜视频 | 亚洲精品成人免费 | 国产一二区视频 | 色插综合 | 成人在线免费视频观看 | 国产亚洲欧美在线视频 | 亚洲精品tv久久久久久久久久 | 狠狠躁夜夜躁人人爽视频 | 日韩欧美一区二区在线播放 | 香蕉视频导航 | 超碰在线人人爱 | 国产免费又粗又猛又爽 | 国产伦理久久 | 国产超碰在线观看 | 视频在线观看国产 | 国产一级二级三级视频 | 欧美日韩一级久久久久久免费看 | 国产精品美女久久久久久免费 | 激情五月五月婷婷 | 91九色网址 | 欧美久久九九 | 一区在线播放 | 最近中文字幕在线中文高清版 | 亚洲国产影院av久久久久 | 久久超级碰 | 伊人激情网 | 久久9999久久免费精品国产 | 91精品国产电影 | 亚洲国产精品电影在线观看 | 国产真实精品久久二三区 | 久久综合中文色婷婷 | 人人射网站 | 国内精品视频一区二区三区八戒 | 狠狠干网址| 成人禁用看黄a在线 | 国产不卡在线 | 精品国产aⅴ麻豆 | 97视频久久久 | 久久久亚洲国产精品麻豆综合天堂 | 亚洲欧美综合精品久久成人 | 99福利片| 精品欧美一区二区在线观看 | 夜夜爽88888免费视频4848 | 欧美日韩高清一区二区三区 | 精品99在线视频 | 国产 av 日韩 | 天天色天天搞 | 三日本三级少妇三级99 | 国产精品大片免费观看 | 成人免费电影 | 日韩成人黄色av | 狠狠色狠狠色综合系列 | 久久国产色 | 在线小视频国产 | 中文字幕国产一区二区 | 中文字幕在线观看视频免费 | 五月婷婷欧美视频 | 91tv国产成人福利 | 激情婷婷在线 | 国产91影院| 狠狠狠干 | 黄色中文字幕在线 | 欧美另类xxx | 国产一区在线不卡 | 成人久久久久久久久久 | 婷婷中文字幕综合 | 97超碰在线视 | 亚洲精品中文字幕视频 | 日韩欧美精品在线观看视频 | 久久中文视频 | 久久高清免费视频 | 四虎永久网站 | 丁香九月婷婷 | 狠狠88综合久久久久综合网 | 一级黄色片在线播放 | 在线观看成人网 | 天天干天天天天 | 国产日韩av在线 | 欧美在线一级片 | 深夜国产在线 | 激情婷婷在线观看 | 国产亚洲精品女人久久久久久 | 亚洲精品中文在线 | 国产精品成人一区二区三区吃奶 | 中文在线免费视频 | 国产日产精品一区二区三区四区 | 欧美在线观看禁18 | 日本精品视频在线观看 | 天天干天天做 | 一区二区精品在线观看 | 成人国产精品久久久久久亚洲 | 国产1区2 | 国产精品小视频网站 | 久久午夜色播影院免费高清 | 精品福利网 | 国产精品一区二 | 9在线观看免费高清完整 | 免费情缘 | 99热高清| 国产精品一区欧美 | 色婷婷激情 | 日韩欧美精品一区二区三区经典 | 中文字幕在线日本 | 97超级碰 | 久久久鲁 | 亚洲精品国产日韩 | 免费日韩 精品中文字幕视频在线 | 九九久久在线看 | 久久久久久久久久久久av | 视频国产精品 | 天天操天天色天天射 | 日产av在线播放 | 激情综合色播五月 | 欧美不卡视频在线 | 在线亚洲欧美日韩 | 国产精品一二三 | 五月婷婷,六月丁香 | 日韩性xxxx| 国产又粗又硬又爽的视频 | 久久国产午夜精品理论片最新版本 | 97看片网 | 97色国产 | 天天操操操操操 | 亚洲男人天堂2018 | 日产乱码一二三区别在线 | av在线激情 | 日韩精品一区电影 | 国产少妇在线观看 | 天天干天天天天 | 欧美日韩精品在线免费观看 | 国产精品一区二区免费看 | 曰本三级在线 | 国产一区二区久久精品 | 日韩精品在线看 | 亚洲一级片免费观看 | 狠狠的操| 欧美亚洲一区二区在线 | 91一区啪爱嗯打偷拍欧美 | 久久福利| www.综合网.com| 欧美日韩在线观看视频 | 久久久蜜桃一区二区 | 麻豆视频免费网站 | 成年人毛片在线观看 | 久久免费的精品国产v∧ | 免费视频 你懂的 | wwwww.国产 | 美女一区网站 | 国产精品久久嫩一区二区免费 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 波多野结衣在线视频一区 | 日韩素人在线观看 | 91夫妻自拍 | 欧美另类网站 | 视频国产在线观看18 | 久久久久欠精品国产毛片国产毛生 | 国产96在线 | 六月丁香综合 | 中文字幕网站视频在线 | 麻豆成人精品视频 | 91亚州 | 四虎影视成人永久免费观看视频 | 在线免费观看麻豆视频 | 人人爽人人看 | 亚洲一区免费在线 | 五月天中文字幕 | 国产91九色蝌蚪 | 色欧美88888久久久久久影院 | 2023国产精品自产拍在线观看 | 国产一区二区不卡视频 | 人人舔人人干 | 91亚洲欧美| 日韩a欧美 | 综合色天天 | 日韩欧美综合精品 | 免费观看成年人视频 | 亚洲激情 欧美激情 | 日韩精品免费在线观看 | 韩国av免费看 | 成人a在线| 又爽又黄又刺激的视频 | 亚洲成人精品国产 | 91在线免费看片 | 欧美伊人网 | 成年人在线观看视频免费 | 成人av在线电影 | 久久免费电影网 | 深夜免费福利在线 | www.夜夜爽 | 9在线观看免费高清完整版 玖玖爱免费视频 | 日本中文字幕在线观看 | 黄网站污 | 国产片网站 | 欧美国产日韩一区二区三区 | av高清网站在线观看 | 亚洲午夜激情网 | 黄色a三级 | 久草在线观 | 久久人人精 | 99精品国产高清在线观看 | 四虎影视av| 特级黄色视频毛片 | 99r在线| 欧美成人日韩 | 国产高清永久免费 | 涩涩在线 | 91视频这里只有精品 | 手机看片国产日韩 | 久章草在线 | 久久久久久久网 | 97超在线 | 在线观看国产日韩欧美 | 一区二区三区在线观看中文字幕 | 成人在线一区二区三区 | 视频三区| 亚洲人在线7777777精品 | 婷婷免费在线视频 | 国产精品一区二区 91 | 日日操日日插 | 五月婷婷丁香色 | 中文字幕不卡在线88 | 69国产精品视频免费观看 | 久久人人97超碰精品888 | 久久99亚洲热视 | 日韩网站在线播放 | 日韩xxxbbb | 久久深夜福利免费观看 | 免费看的黄色片 | 中文字幕在线国产 | 亚洲三级国产 | 91精品久久久久久综合乱菊 | 天天干天天射天天爽 | 亚洲精品视频观看 | 久久久 精品 | 成人免费视频a | 午夜av免费观看 | www.888av| 玖操 | 999国内精品永久免费视频 | 欧美日韩视频在线播放 | 日本美女xx | 免费av在线| 久久久久久影视 | 国产精品美女免费视频 | 在线a亚洲视频播放在线观看 | 精品国产综合区久久久久久 | 国产精品久久久久久久久搜平片 | www久久com| 少妇搡bbbb搡bbb搡忠贞 | 亚洲草视频 | 亚洲热久久| 91精品国产网站 | 一区二区三区韩国免费中文网站 | 香蕉97视频观看在线观看 | 中文在线a∨在线 | 国产成人精品免高潮在线观看 | a黄色片| 国产涩涩网站 | 欧美日韩国产精品久久 | 免费三级av | 天天色综合1 | 精品久久久久久久久中文字幕 | 高清av免费一区中文字幕 | 二区三区av| 欧美激情综合色综合啪啪五月 | 日本深夜福利视频 | 91网免费观看 | 亚洲永久精品在线观看 | 一区二区三区视频 | 激情欧美在线观看 | 亚洲精品在线视频 | 香蕉在线播放 | 中文字幕在线日 | 蜜臀久久99精品久久久久久网站 | 在线视频麻豆 | 日本久久久久久久久久 | 在线观看色网站 | 精品嫩模福利一区二区蜜臀 | 国产女人40精品一区毛片视频 | 91av视频在线免费观看 | 日本黄色大片儿 | 在线日韩视频 | 在线精品视频免费播放 | 成人久久免费视频 | 欧美老人xxxx18 | 精品国产乱码久久久久久天美 | 日韩黄色在线观看 | 色综合亚洲精品激情狠狠 | 国产在线免费观看 | 国产h在线播放 | 国产中文字幕在线免费观看 | 欧美在线一 | 日本中文字幕网 | 毛片视频网址 | 中文字幕91视频 | 色婷婷狠狠五月综合天色拍 | 中文字幕日韩国产 | 狠狠狠狠狠狠 | 久久免费播放视频 | 在线国产视频一区 | 91在线免费观看网站 | 麻豆一精品传二传媒短视频 | 99久久国产免费,99久久国产免费大片 | 在线午夜电影神马影院 | 久久天天综合网 | 免费99精品国产自在在线 | 97精品一区二区三区 | 丁香九月激情综合 | 狠狠色丁香婷婷综合久小说久 | 亚洲永久精品视频 | 99精品视频免费看 | 欧美精品久久久久久久久免 | 在线网站黄 | va视频在线 | 国产精品小视频网站 | 91精品办公室少妇高潮对白 | 亚洲在线视频免费观看 | 免费福利在线观看 | 日韩一区视频在线 | 欧美综合在线视频 | 成人一级片视频 | 久久久这里有精品 | 911精品美国片911久久久 | 欧美日韩在线视频观看 | 成人av观看 | 97在线观看视频 | 午夜精品久久久久久99热明星 | 97热久久免费频精品99 | ,久久福利影视 | 亚洲精品xx | 国产又粗又硬又爽视频 | www.天天色.com | 久久国产影视 | 天天综合91| 又黄又爽的视频在线观看网站 | 国产综合小视频 | 91亚洲精品在线观看 | 五月天六月婷婷 | 亚洲日本中文字幕在线观看 | 久久久久久久影院 | 日日干天天操 | 99久久久国产免费 | 久久综合偷偷噜噜噜色 | 91精品在线免费 | 成人a在线观看高清电影 | 国产剧情av在线播放 | 4p变态网欧美系列 | 91av免费在线观看 | 五月天久久久久 | www.av免费| 欧美韩国日本在线 | 91中文视频 | 蜜桃视频在线观看一区 | 亚洲日本三级 | 国产片网站 | 日韩在线国产精品 | 国产黄色大片 | av在线官网 | 国产91aaa| 射射射综合网 | 狠狠干激情 | 日韩三级在线观看 | 黄色av高清 | 中文一区在线观看 | 亚洲天堂网在线播放 | 免费观看一级 | 高清国产午夜精品久久久久久 | 日韩二三区 | 91中文字幕网 | 成人a免费 | 少妇精品久久久一区二区免费 | 高清精品在线 | 色婷婷激情综合 | 97国产 | 蜜臀久久99精品久久久无需会员 | 国产黄色精品在线 | 成年人免费av | 91精品国产欧美一区二区 | 久久久久久高潮国产精品视 | 国产精品免费av | 久久久久久毛片 | 久久99爱视频 | 国产一区二区在线免费 | 久久经典国产 | 国产精品免费观看视频 | 日韩免费视频在线观看 | 亚洲精品综合欧美二区变态 | 欧美久草视频 | 免费av网址在线观看 | 福利视频午夜 | 国产精品二区三区 | 香蕉网站在线观看 | 免费观看日韩av | 狠狠干天天色 | 精品嫩模福利一区二区蜜臀 | 久久夜色精品国产欧美乱极品 | 天天天天天干 | 久草精品视频 | 国产麻豆电影 | 欧美一级视频在线观看 | 黄色综合| 97精品久久人人爽人人爽 | 亚洲精品久久久久久国 | 99热国产在线观看 | 精品亚洲午夜久久久久91 | 免费中文字幕 | 在线免费性生活片 | 国产中文视频 | 日本中文乱码卡一卡二新区 | 激情久久久 | 91精品国产九九九久久久亚洲 | 国产精品白虎 | 国产黄色在线 | 99在线精品视频在线观看 | 一区二区三区免费在线 | 成年人在线免费看视频 | 欧美午夜理伦三级在线观看 | 日日夜夜人人精品 | 国产一区免费看 | 国产91精品看黄网站在线观看动漫 | 欧美精品二区 | 在线观看 国产 | 二区视频在线观看 | 久久色网站 | 日本精品视频在线观看 | 午夜精品福利一区二区三区蜜桃 | 免费看一级特黄a大片 | 日韩在线短视频 | 国产视频18 | 在线看日韩 | 婷婷激情综合 | 在线观看的av | 亚洲精品456在线播放乱码 | 精品久久久久久久久久久久久 | 久久成人午夜视频 | 99久久精品免费 | 69视频永久免费观看 | 又黄又爽又湿又无遮挡的在线视频 | 亚洲女同videos | 婷婷网在线 | 欧美午夜性生活 | 亚洲精品日韩在线观看 | 丁香婷婷综合激情五月色 | www黄在线 | 久久这里只有精品23 | 国产中文字幕av | 色婷婷中文| 97精品一区 | 91香蕉视频黄色 | 久久黄页 | 国产精品永久免费视频 | 免费v片| 国产精品毛片久久 | 五月开心激情 | 国产v在线播放 | 手机在线黄色网址 | 国产又粗又猛又黄又爽 | 91免费在线播放 | 波多野结衣在线视频一区 | 国产高清在线免费观看 | 国产精品一区二区三区电影 | 国产成人综合图片 | 国产视频在线观看一区二区 | 久久中文字幕视频 | 午夜久久久久久久久久影院 | 激情婷婷在线 | 久久综合五月天婷婷伊人 | 色香蕉在线 | 亚洲精品免费在线视频 | 欧美另类重口 | 亚洲色五月 | 中文字幕91 | 亚洲视频2| 日韩久久视频 | 国产免费嫩草影院 | 国产视频一区在线免费观看 | 国产成人一区二区三区免费看 | 三三级黄色片之日韩 | 成人av在线资源 | www视频在线播放 | 国产黄色精品在线观看 | 中文字幕久久精品亚洲乱码 | 黄色片网站| 天天色综合久久 | 91精品对白一区国产伦 | 免费在线观看国产精品 | 欧美日韩精品国产 | 狠狠88综合久久久久综合网 | 日日夜夜天天干 | www天天干 | 99久久99久国产黄毛片 | 国产99在线| 人人干人人干人人干 | 久久免费的精品国产v∧ | 人人插人人插 | 在线91播放 | 久久久免费高清视频 | 97精品国自产拍在线观看 | 黄色小网站在线观看 | 九九久久久 | 天堂网一区二区 | 日韩精品无码一区二区三区 | 天天操天天干天天爽 | 日韩二区在线播放 | 午夜久久久久久久久 | 日韩r级电影在线观看 | 91精品在线播放 | 免费a v网站 | 色偷偷网站视频 | 欧美一进一出抽搐大尺度视频 | 天天拍天天干 | 视频一区视频二区在线观看 | 99精品偷拍视频一区二区三区 | 手机在线看a | 丝袜一区在线 | 久久一区二区三区日韩 | 九色精品免费永久在线 | 日本久久成人 | 国产在线高清精品 | av丁香| 亚洲丝袜一区 | 中文字幕亚洲欧美日韩2019 | 国产区高清在线 | 色久天| 欧美地下肉体性派对 | 免费看的国产视频网站 | 欧美激情视频一二区 | 麻豆影视在线免费观看 | 久草视频中文在线 | 国产精品久久久久久影院 | 粉嫩av一区二区三区四区 | 免费在线观看av网址 | 久久久亚洲麻豆日韩精品一区三区 | 亚洲一区二区高潮无套美女 | 三级黄色网址 | 这里只有精品视频在线观看 | 国产无区一区二区三麻豆 | 国产精品久久网站 | 久草综合在线观看 | 一区二区视频免费在线观看 | 伊人久久在线观看 | 亚洲成熟女人毛片在线 | 91色蜜桃| 成人av免费看 | 免费在线色电影 | 久草免费手机视频 | 欧美日韩亚洲在线观看 | 丁香花在线视频观看免费 | 最近日韩中文字幕中文 | 狠狠干天天色 | 日韩精品一区二区三区第95 | 免费视频黄色 | 黄色免费国产 | 夜夜视频 | 国产精品久久久久影院 | 天天伊人狠狠 | 在线观看精品一区 | 午夜婷婷在线观看 | 国内精品视频一区二区三区八戒 | 国产成人久久av免费高清密臂 | 欧美日在线观看 | 国产自产在线视频 | 久久久激情视频 | 丁香婷婷激情啪啪 | 亚洲人人网 | 69国产盗摄一区二区三区五区 | 国产中文字幕视频在线 | 亚洲精品视频在线观看免费视频 | 91免费在线看片 | 中文字幕丰满人伦在线 | 国产麻豆精品95视频 | 色综合久久久久综合 | 国产91免费观看 | 亚洲精品一区中文字幕乱码 | 精品国产三级a∨在线欧美 免费一级片在线观看 | www.色com| 欧美国产精品久久久久久免费 | 久久久久成人精品 | 久久精品欧美日韩精品 | 91夫妻视频 | 免费观看91视频 | 天天人人| 国产高清在线免费观看 | 人人插超碰 | 国产精品成人免费一区久久羞羞 | 99久久精品一区二区成人 | av东方在线| 丁香激情视频 | 国产一级视频免费看 | 亚洲日本一区二区在线 | 久久国产精品免费一区二区三区 | 日本精品久久久久久 | 精品 一区 在线 | 丁香六月色 | 欧美日韩视频 | 免费看v片 | 九热精品 | 在线v片免费观看视频 | 91在线免费视频观看 | 亚洲va韩国va欧美va精四季 | www.xxxx变态.com | 久久人人爽av | av在线免费在线观看 | 国产精品久久99精品毛片三a | 91香蕉国产| 丁香花在线视频观看免费 | 久久五月婷婷丁香 | 久久国产精品99久久久久久丝袜 | 99热这里只有精品在线观看 | 97综合视频 | 精品久久久久免费极品大片 | 亚洲激精日韩激精欧美精品 | 在线视频 你懂得 | 2020天天干夜夜爽 | 日韩欧美一区二区在线播放 | 国产精品美女久久久久aⅴ 干干夜夜 | 成人av中文字幕在线观看 | 在线免费黄色毛片 | 亚洲视频电影在线 | 久久99久久99精品中文字幕 | 成人一区二区在线 | 黄色成人91 | av在线最新| 中文字幕在线观看视频免费 | 天天操天天是 | 免费观看日韩av | 一区二区三区在线电影 | 久久久福利视频 | 西西444www大胆高清图片 | 国产精品资源在线观看 | 婷婷六月综合亚洲 | 国产成人精品免高潮在线观看 | 黄网在线免费观看 | 四季av综合网站 | 日韩va在线观看 | 中文字幕中文字幕在线中文字幕三区 | 色94色欧美 | 999久久| av一区在线 | 中文字幕一区在线观看视频 | 在线视频1卡二卡三卡 | 爱av在线网 | 99亚洲精品 | 欧美a级一区二区 | 黄色免费电影网站 | www激情com | 亚洲在线高清 | 中文字幕日本电影 | 嫩草伊人久久精品少妇av | 激情开心网站 | 亚洲国产免费看 | h视频在线看 | 视频二区 | av黄色av| 中文字幕乱码电影 | 中文字幕中文字幕在线一区 | 91香蕉嫩草 | 久久久久久免费 | 亚洲综合在线五月 | 在线观看91| 亚洲草视频| 成人a免费| 九九九九九国产 | 久热只有精品 | 日日麻批40分钟视频免费观看 | 国产一区二区日本 | 亚洲aⅴ免费在线观看 | a√天堂中文在线 | 中文字幕在线中文 | 国产一区二区三区免费观看视频 | 亚洲国产日韩在线 | 日韩精品视频在线观看网址 | 国产一区二区三区免费观看视频 | 中文在线免费一区三区 | 欧美日韩午夜在线 | 深夜激情影院 | 天天干天天操天天射 | 久久久国产日韩 | 久久精品视频在线观看 | 亚洲五月婷婷 | 91视频xxxx| 毛片网站在线观看 | 日韩 在线a| 丰满少妇在线观看 | 狠狠干婷婷| 久久99婷婷 | 天天天天色综合 | 最新中文字幕视频 | 香蕉视频日本 | 99视屏| 日韩影视大全 | 成人亚洲免费 | 欧美在线视频日韩 | www成人精品| 成人久久18免费网站 | 国产精品久久久久久久久久免费 | 国产精品永久免费观看 | 日韩av电影中文字幕在线观看 | 久久久在线免费观看 | 成人一区二区在线观看 | 在线播放日韩av | 亚洲涩涩网站 | 伊人久久国产精品 | 亚洲人成在线电影 | 国产日产精品一区二区三区四区 | 99久久精品免费一区 | 99在线观看 | 国产精品久久久久久模特 | 在线观看黄网站 | 天天操月月操 | 日韩成人精品一区二区三区 | 欧美黄色成人 |