亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS實現手勢滑動解鎖功能簡析

2020-07-26 02:38:38
字體:
來源:轉載
供稿:網友

題記

在平常的生活中,我們大概經常遇見手勢滑動解鎖---也就是九宮格啊,已經出現好久了,雖然隨著Apple的指紋解鎖的發展手勢解鎖雖然還有但是因為其不如指紋解鎖方便也用的也少了,但是在大多數APP中這兩種方式都是并存的,比如qq,微信,支付寶等等,最近項目里面也剛好有這個需求,趁著剛完成抽出時間來記錄下來當時的一些思路,可能有的地方理解的不到位,還需多總結,閑言少敘了,看重點。

功能描述如圖:大概說一下思路,這個功能用來做相當于密令,用于兩端的匹配,教師端設置了路徑生成密碼,儲存在本地,學生端用來滑動輸入進行驗證。然后根據各種情況上部的label給與各種提示信息,這里只是一個比較原始簡陋的demo,也只是實現了我們最常見的功能,所以重在領會其中的精神了,哈哈哈。


功能模塊分析

根據GIF可以簡單的把這塊兒功能分為幾個部分來理解,第一個就是首頁:ViewController,首頁里面有兩個Controller分別是StudViewController和TeacViewController用來分作不同功能的載體。在StudViewController中分為三部分上中下statusLabel GestureLockView clearBtn,其中GestureLockView是手勢解鎖界面。在TeacViewController中也是分為三部分,statusLabel GestureLockView BottomView下方的bottomView分為兩個button resetBtn重置按鈕和sureBtn確定按鈕。說完大體的結構,接下來分部分說一下每個功能的實現思路。

拆解分析

首先說一下GestureLockView這個view控件:

首先在.h 文件中

定義兩個枚舉:分別用來定義兩端的不同類型,stu端用ResultKindType來對畫的手勢結果進行分類分為這四類,下面都會用到,并說明用途。teac端用TeacKindType來分兩類:

//檢測手勢密碼答案情況 對/錯/不夠4個數字typedef NS_ENUM(NSUInteger, ResultKindType) {  ResultKindTypeTrue,  ResultKindTypeFalse,  ResultKindTypeNoEnough,  ResultKindTypeClear};typedef NS_ENUM(NSUInteger, TeacKindType) {  TeacKindTypeNoEnough,  TeacKindTypeTrue};

協議:用來監聽手勢變化時傳出的轉化的密碼(這個密碼是用button的tag值來表示的),因為手勢是在變化的,所以這里用了NSMutableString向外傳遞。

@protocol GestureLockDelegate <NSObject>- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword;@end

屬性:

  1. @property (nonatomic, weak) id<GestureLockDelegate> delegate;
  2. @property (nonatomic, assign) BOOL isTeac;//教師端 用來驗證是否是教師端

方法:

- (void)clearLockView;//清除布局 重新開始- (void)checkPwdResult:(ResultKindType)resultType;//檢測學生端的結果- (void)checkTeacResult:(TeacKindType)resultType;//檢測老師端的結果

.m文件中(具體創建和應用的方法)

聲明變量供下方使用:

@interface GestureLockView ()@property (strong, nonatomic) NSMutableArray *selectBtns;//選中的按鈕數組@property (nonatomic, strong) NSMutableArray *errorBtns;//錯誤的按鈕數組@property(nonatomic, assign)BOOL finished;//是否完成@property (nonatomic, assign) CGPoint currentPoint;//當前觸摸點@property (nonatomic, assign) ResultKindType resultType;//學生端結果@property (nonatomic, assign) TeacKindType teacResultType;//教師端結果@end

懶加載初始化數組

- (NSMutableArray *)selectBtns {  if (!_selectBtns) {    _selectBtns = [NSMutableArray array];  }  return _selectBtns;}- (NSMutableArray *)errorBtns {  if (!_errorBtns) {    _errorBtns = [NSMutableArray array];  }  return _errorBtns;}

子視圖初始化:在這里創建9個按鈕并將它們add到self中,并給self 添加UIPanGestureRecognizer *pan手勢

- (void)initSubviews {  self.backgroundColor = [UIColor clearColor];  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];  [self addGestureRecognizer:pan];    //創建9個按鈕  for (NSInteger i = 0; i < 9; i++) {    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];    btn.userInteractionEnabled = NO;    [btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];    [btn setImage:[UIImage imageNamed:@"sign_img_circle_s"] forState:UIControlStateSelected];    btn.tag = i+1;    [self addSubview:btn];  }}

界面布局:

  CGFloat minWidth = MIN(self.bounds.size.height, self.bounds.size.width);  CGFloat boundsWidth = self.bounds.size.width;  CGFloat margin = (minWidth - cols * w) / (cols + 1);//間距  CGFloat xMargin = (boundsWidth-2*margin-3*w)/2;

這里這一塊是對不同機型進行的適配,因為這個控件有可能會被添加在一個height<width的view上,所以在這里margin是指比較短的長度也就是上下的height,xMargin是用來對width進行伸展的,這塊是這個邏輯,應該可以通用的。

- (void)layoutSubviews {  [super layoutSubviews];  NSUInteger count = self.subviews.count;  int cols = 3;//總列數  CGFloat x = 0,y = 0,w = 0,h = 0;  if (SCREEN_WIDTH == 320) {    w = 50;    h = 50;  } else {    w = 60;    h = 60;  }  CGFloat minWidth = MIN(self.bounds.size.height, self.bounds.size.width);  CGFloat boundsWidth = self.bounds.size.width;  CGFloat margin = (minWidth - cols * w) / (cols + 1);//間距  CGFloat xMargin = (boundsWidth-2*margin-3*w)/2;    CGFloat col = 0;  CGFloat row = 0;  for (int i = 0; i < count; i++) {    col = i % cols;    row = i / cols;    if (i == 0 || i == 3 || i == 6) {      x = xMargin;    } else if (i == 1 || i == 4 || i == 7) {      x = xMargin + w + margin;    } else {      x = xMargin + 2 * (margin+w);    }    y = (w+margin)*row;    UIButton *btn = self.subviews[i];    btn.frame = CGRectMake(x, y, w, h);  }}

手勢代理方法: 在手勢代理方法中監聽手勢滑動位置的改變,當pan.state == UIGestureRecognizerStateBegan開始滑動的時候,從盛放顯示錯誤狀態的button改變為普通初始狀態,并且將self.errorBtns數組清除。將_currentPoint = [pan locationInView:self];檢測當滑動時當前的位置point,如果劃過的位置包含在button的范圍內,如果button.selected == NO那么將button.selected = YES;//設置為選中并且將button添加到self.selectBtns數組中[self.selectBtns addObject:button];調用[self setNeedsDisplay];方法進行重繪,調用setNeedsDisplay方法系統會自動調用drawReact方法進行界面的重新布局。最后監聽手指是否松開//監聽手指松開 if (pan.state == UIGestureRecognizerStateEnded) { self.finished = YES; }如果松開將self.finished = YES;

#pragma mark 手勢- (void)pan:(UIPanGestureRecognizer *)pan {    if (pan.state == UIGestureRecognizerStateBegan) {    for (UIButton *btn in _errorBtns) {      [btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];      [btn setImage:[UIImage imageNamed:@"sign_img_circle_s"] forState:UIControlStateSelected];    }    [self.errorBtns removeAllObjects];  }  _currentPoint = [pan locationInView:self];    for (UIButton *button in self.subviews) {    if (CGRectContainsPoint(button.frame, _currentPoint)) {      if (button.selected == NO) {        //點在按鈕上        button.selected = YES;//設置為選中        [self.selectBtns addObject:button];      } else {              }    }  }    //重繪  [self setNeedsDisplay];  //監聽手指松開  if (pan.state == UIGestureRecognizerStateEnded) {    self.finished = YES;  }}

傳遞設置的手勢密碼方法

//傳遞設置的手勢密碼- (NSMutableString *)transferGestureResult {  //創建可變字符串  NSMutableString *result = [NSMutableString string];  for (UIButton *btn in self.selectBtns) {    [result appendFormat:@"%ld", btn.tag - 1];  }  return result;}

兩端的外部操作對內部狀態的改變:

case ResultKindTypeFalse:_errorBtns = [NSMutableArray arrayWithArray:self.selectBtns];break;

這里如果繪制錯誤,將之前選中的按鈕放在 _errorBtns盛放錯誤按鈕的數組中

case ResultKindTypeClear:{[[UIColor clearColor] set];for (int i = 0; i < self.errorBtns.count; i++) {UIButton *btn = [self.errorBtns objectAtIndex:i];[btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];}[self.errorBtns removeAllObjects];}break;

當外界改變狀態為“清除”時,將路徑置為透明 并改變errorBtns數組中button的背景色狀態,并且將errorBtns清空,這里為什么在這里做這些改變呢?這是因為在學生端進行清除操作的時候,手勢的狀態已經是finish并且這是后代理方法已經走完,并且我們在調用clearLockView方法的時候也將selectBtns數組清空了,因此在setNeedsDisplay被調用,drawReact進行重繪的時候,檢測到if (_selectBtns.count == 0) return;也就不再繼續往下進行了。

//學生端狀態改變- (void)checkPwdResult:(ResultKindType)resultType {  self.resultType = resultType;  switch (resultType) {    case ResultKindTypeFalse:      _errorBtns = [NSMutableArray arrayWithArray:self.selectBtns];      break;      case ResultKindTypeTrue:      break;      case ResultKindTypeNoEnough:      break;      case ResultKindTypeClear:    {      [[UIColor clearColor] set];      for (int i = 0; i < self.errorBtns.count; i++) {        UIButton *btn = [self.errorBtns objectAtIndex:i];        [btn setImage:[UIImage imageNamed:@"sign_img_circle_n"] forState:UIControlStateNormal];      }      [self.errorBtns removeAllObjects];    }      break;    default:      break;  }  [self clearLockView];}//教師端狀態改變- (void)checkTeacResult:(TeacKindType)resultType {  self.teacResultType = resultType;  switch (resultType) {    case TeacKindTypeTrue:      break;    case TeacKindTypeNoEnough:{      [self clearLockView];    }      break;    default:      break;  }}

清除方法: 這里將self.finished = NO;因為如果是通過代理將值傳到外界并且外界對該值進行了校驗,對內容的resultType進行改變,這時候其實還是在drawReact方法中,并且已經走完了self.finished 方法,在這里將其設置為NO 是為了改變下一次繪制的finished狀態,雖然不起眼,但是也是寫出來了。

- (void)clearLockView {  self.finished = NO;  //遍歷所有選中的按鈕  for (UIButton *btn in self.selectBtns) {    //取消選中狀態    btn.selected = NO;  }  [self.selectBtns removeAllObjects];  //  [self setNeedsDisplay];}

利用貝塞爾曲線繪制路徑,并根據對應的狀態修改路徑顏色,按鈕顏色,當系統調用這個方法的時候會進行重繪,重繪時,從self.selectBtns數組中取出選中的button,當button是第一個的時候將其設置為bezierPath的起點[path moveToPoint:btn.center];其余的按鈕繪制路徑[path addLineToPoint:btn.center];。在這里判斷是否松開手指,在這個判斷里邏輯判斷比較多,大致捋一下,當self.finished == YES的時候,就將創建的密碼利用先前聲明的代理傳遞出去在外部進行檢驗。根據外部返回的操作狀態,如果是self.isTeac根據返回的結果狀態進行判斷

case TeacKindTypeNoEnough:{[[UIColor clearColor] set];}break;case TeacKindTypeTrue:{[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];}

如果畫的點不足4個,那么清除選中的點并且將繪制路徑的顏色透明(或者如果考慮到性能的話,最好用和背景色一樣的顏色),如果是繪制完成,用“綠色”填充,這里我選擇了教師繪制完畢不清楚繪制路徑,以便查看。
如果是學生端的話:繪制正確清除路徑,錯誤用“紅色”標識路徑并從盛放錯誤按鈕的數組self.errorBtns中取出按鈕進行狀態的改變。

switch (self.resultType) {case ResultKindTypeTrue:{//正確[[UIColor clearColor] set];}break;case ResultKindTypeFalse:{//錯誤[[UIColor redColor] set];for (int i = 0; i < self.errorBtns.count; i++) {UIButton *btn = [self.errorBtns objectAtIndex:i];[btn setImage:[UIImage imageNamed:@"sign_img_circle_p"] forState:UIControlStateNormal];}break;case ResultKindTypeNoEnough:{[[UIColor clearColor] set];}break;case ResultKindTypeClear:break;default:break;}

之后便是若沒有finish 就是在繪制路徑了,對path進行一些相關設置。

- (void)drawRect:(CGRect)rect {  if (_selectBtns.count == 0) return;  // 把所有選中按鈕中心點連線  UIBezierPath *path = [UIBezierPath bezierPath];  for (int i = 0; i < self.selectBtns.count; i ++) {    UIButton *btn = self.selectBtns[i];    if (i == 0) {      [path moveToPoint:btn.center]; // 設置起點    } else {      [path addLineToPoint:btn.center];    }  }    //判斷是否松開手指  if (self.finished) {    //松開手    NSMutableString *pwd = [self transferGestureResult];//傳遞創建的密碼    [[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];    if ([self.delegate respondsToSelector:@selector(gestureLockView:drawRectFinished:)]) {      [self.delegate gestureLockView:self drawRectFinished:pwd];    }        if (self.isTeac) {      //教師端      switch (self.teacResultType) {        case TeacKindTypeNoEnough:        {          [[UIColor clearColor] set];        }          break;        case TeacKindTypeTrue:        {          [[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];        }          break;        default:          break;      }    } else {      switch (self.resultType) {        case ResultKindTypeTrue:        {          //正確          [[UIColor clearColor] set];        }          break;        case ResultKindTypeFalse:        {          //錯誤          [[UIColor redColor] set];          for (int i = 0; i < self.errorBtns.count; i++) {            UIButton *btn = [self.errorBtns objectAtIndex:i];            [btn setImage:[UIImage imageNamed:@"sign_img_circle_p"] forState:UIControlStateNormal];          }          break;        case ResultKindTypeNoEnough:          {            [[UIColor clearColor] set];          }          break;        case ResultKindTypeClear:          break;        default:          break;        }      }        }  } else {    [path addLineToPoint:self.currentPoint];    [[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];  }  path.lineWidth = 1;  path.lineJoinStyle = kCGLineCapRound;  path.lineCapStyle = kCGLineCapRound;  [path stroke];}

ViewController

這個比較容易理解:分別跳轉兩個界面:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  if (indexPath.row == 0) {    TeacViewController *vc = [[TeacViewController alloc] init];    [self.navigationController pushViewController:vc animated:YES];  } else {    StudViewController *vc = [[StudViewController alloc] init];    [self.navigationController pushViewController:vc animated:YES];  }}

TeacViewController

主要的應用就是調用GestureLockViewDelegate了,接受并校驗密碼,

#pragma mark gestureLockView代理事件- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword {  [self createGesturesPassword:gesturePassword];}//創建手勢密碼- (void)createGesturesPassword:(NSMutableString *)gesturePassword {  if (self.lastGesturePsw.length == 0) {    if (gesturePassword.length < 4) {      self.lastGesturePsw = nil;      [self.gestureLockView checkTeacResult:TeacKindTypeNoEnough];      self.statusLabel.text = @"至少連接4個點,重新輸入";      [self shakeAnimationForView:self.statusLabel];      return;    }    self.lastGesturePsw = gesturePassword;    [self.gestureLockView checkTeacResult:TeacKindTypeTrue];    NSLog(@"---%@", self.lastGesturePsw);    self.statusLabel.text = [NSString stringWithFormat:@"密碼是%@", gesturePassword];  }}

兩個按鈕的點擊事件

#pragma mark 按鈕點擊事件//重置按鈕- (void)resetBtnClick:(UIButton *)btn {  self.lastGesturePsw = nil;  [TeacViewController addGesturePassword:@""];  [self.gestureLockView checkTeacResult:TeacKindTypeNoEnough];  self.statusLabel.text = @"請繪制手勢密碼";  NSLog(@"resetPwd == %@, resetUserDefaultsPwd == %@", self.lastGesturePsw, [TeacViewController gesturePassword]);}//確定按鈕- (void)sureBtnClick:(UIButton *)btn {  if (!self.lastGesturePsw) {    self.statusLabel.text = @"請繪制手勢密碼";    return;  }  [TeacViewController addGesturePassword:self.lastGesturePsw];  [self.gestureLockView checkTeacResult:TeacKindTypeTrue];  self.statusLabel.text = @"密碼設置成功";  NSLog(@"resetPwd == %@, resetUserDefaultsPwd == %@", self.lastGesturePsw, [TeacViewController gesturePassword]);//  [self.navigationController popViewControllerAnimated:YES];}

用本地存儲進行模擬

#pragma mark 本地存儲模擬+ (void)deleteGestuesPassword {  [[NSUserDefaults standardUserDefaults] removeObjectForKey:GESPWD];  [[NSUserDefaults standardUserDefaults] synchronize];}+ (void)addGesturePassword:(NSString *)gesturePassword {  [[NSUserDefaults standardUserDefaults] setObject:gesturePassword forKey:GESPWD];  [[NSUserDefaults standardUserDefaults] synchronize];}+ (NSString *)gesturePassword {  return [[NSUserDefaults standardUserDefaults] objectForKey:GESPWD];}

StudViewController

GestureLockDelegate代理方法 并校驗對當前的手勢密碼和本地存儲的教師端密碼

#pragma mark 手勢密碼界面代理- (void)gestureLockView:(GestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword {  [self validateGesturePassword:gesturePassword];}//校驗手勢密碼- (void)validateGesturePassword:(NSMutableString *)gesturePassword {    if (gesturePassword.length < 4) {    self.statusLabel.text = @"至少連接4個點,重新輸入";    [self.gestureLockView checkPwdResult:ResultKindTypeNoEnough];    [self shakeAnimationForView:self.statusLabel];    return;  }  self.lastGesturePsw = gesturePassword;      /*滑完直接校驗*/  NSLog(@"validPwd == %@, validUserDefaultsPwd == %@", self.lastGesturePsw, [StudViewController gesturePassword]);  static NSInteger errorCount = 5;    if ([self.lastGesturePsw isEqualToString:[StudViewController gesturePassword]]) {    [self.gestureLockView checkPwdResult:ResultKindTypeTrue];    self.statusLabel.text = @"密碼校驗成功";    [self shakeAnimationForView:self.statusLabel];  } else {    [self.gestureLockView checkPwdResult:ResultKindTypeFalse];    errorCount = errorCount - 1;    if (errorCount == 0) {      //已經輸錯5次      self.statusLabel.text = @"請重新輸入密碼";      errorCount = 5;      return;    }    self.statusLabel.text = [NSString stringWithFormat:@"密碼錯誤, 還可以再輸入%ld次", errorCount];    [self shakeAnimationForView:self.statusLabel];  }}

清除按鈕點擊事件 改變self.gestureLockView中的resultType 進行界面的重繪等調整

- (void)clearBtnClick:(UIButton *)btn {  self.statusLabel.text = @"清除!!!";  [self.gestureLockView checkPwdResult:ResultKindTypeClear];  [self shakeAnimationForView:self.statusLabel];}

本地存儲:這里也有一個本地存儲 和教師端對應 (其實可以單獨封裝出來的)

#pragma mark 本地存儲模擬+ (void)deleteGestuesPassword {  [[NSUserDefaults standardUserDefaults] removeObjectForKey:GESPWD];  [[NSUserDefaults standardUserDefaults] synchronize];}+ (void)addGesturePassword:(NSString *)gesturePassword {  [[NSUserDefaults standardUserDefaults] setObject:gesturePassword forKey:GESPWD];  [[NSUserDefaults standardUserDefaults] synchronize];}+ (NSString *)gesturePassword {  return [[NSUserDefaults standardUserDefaults] objectForKey:GESPWD];}

以上,就是這個功能實現的大體流程了,捋順了思路來看其實還是蠻明確的,當時做的時候也是走路挖坑填坑的,發現這樣把自己的思路寫下來還真是蠻有收獲的,希望自己更好的進步,如果您看到這兒覺得有不合理的地方歡迎隨時和我溝通哈。

源代碼連接:https://github.com/irembeu/LGJGestureLockDemo.git

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品欧美日韩一区二区| 欧美黄色三级网站| 欧美在线观看一区二区三区| 亚洲人成网7777777国产| 久久精品影视伊人网| 亚洲综合色激情五月| 在线精品高清中文字幕| 欧美午夜影院在线视频| 国产视频精品一区二区三区| 亚洲成色777777女色窝| 亚洲综合精品伊人久久| 欧美在线不卡区| 红桃视频成人在线观看| 萌白酱国产一区二区| 国产福利精品在线| 欧美性感美女h网站在线观看免费| 91久久久久久久久久| 日韩中文字幕不卡视频| 国产成人自拍视频在线观看| 97不卡在线视频| 亚洲国产欧美一区二区三区同亚洲| 色播久久人人爽人人爽人人片视av| 久久久久久久久国产| 精品久久久久久亚洲精品| 亚洲激情在线观看视频免费| 欧美性高跟鞋xxxxhd| 亚洲九九九在线观看| 国产精品丝袜高跟| 日韩高清电影免费观看完整| 日韩亚洲综合在线| 国产精品流白浆视频| 欧美大片大片在线播放| 国产精品情侣自拍| 欧美成人免费va影院高清| 亚洲在线观看视频网站| 日韩精品久久久久久久玫瑰园| 国产精品日本精品| 国产精品稀缺呦系列在线| 久久精品国产久精国产思思| 欧美国产高跟鞋裸体秀xxxhd| 伊人久久大香线蕉av一区二区| 97人洗澡人人免费公开视频碰碰碰| 国产99久久精品一区二区 夜夜躁日日躁| 欧美在线免费观看| 亚洲视频在线观看网站| 国产mv久久久| 欧美综合第一页| 国产欧美日韩综合精品| 91久久国产精品| 国产一区二区三区在线播放免费观看| 日韩hd视频在线观看| 亚洲人成电影在线播放| 欧美日韩视频免费播放| 色综合久久久久久中文网| 精品丝袜一区二区三区| 亚洲精品97久久| 国产日韩精品一区二区| 成人www视频在线观看| 中文字幕一区二区三区电影| 欧美小视频在线| 亚洲精品在线视频| 亚洲国产欧美自拍| www国产91| 热re91久久精品国99热蜜臀| 国产成人av在线播放| 精品无人国产偷自产在线| 中文字幕精品一区久久久久| 久久久久九九九九| 中文字幕少妇一区二区三区| 狠狠躁天天躁日日躁欧美| 欧洲亚洲妇女av| 久久久成人的性感天堂| 韩国三级日本三级少妇99| 精品久久久香蕉免费精品视频| 久久久噜久噜久久综合| 日韩大片在线观看视频| 91精品国产高清自在线| 国产精品一区二区三| 欧美日韩国产中字| 久久伊人精品天天| 国产午夜精品全部视频在线播放| 性色av一区二区咪爱| 欧美激情性做爰免费视频| 亚洲第一视频网站| 欧美日韩成人黄色| 4438全国成人免费| 91日韩在线播放| 亚洲97在线观看| 精品久久中文字幕| 欧美日韩中文字幕在线| 97国产suv精品一区二区62| 中文字幕日韩综合av| 国产精品久久久久影院日本| 亚洲区免费影片| 欧美精品久久久久久久| 久久在线免费观看视频| 国产z一区二区三区| 菠萝蜜影院一区二区免费| 91午夜理伦私人影院| 久久久国产精品免费| 亚洲性av在线| 狠狠操狠狠色综合网| 欧美激情欧美激情| 久久久久久久久久久久av| 97在线日本国产| 久久久久久久久国产精品| 97久久精品视频| 国产精品久久999| 欧美日韩在线免费观看| 中文字幕在线日韩| 久久韩国免费视频| 色悠悠国产精品| 蜜臀久久99精品久久久无需会员| 国产视频精品一区二区三区| 欧美激情成人在线视频| 久久久亚洲网站| 欧美中文在线观看| 久久91亚洲精品中文字幕| 26uuu国产精品视频| 国产在线久久久| 波霸ol色综合久久| 久久久中文字幕| 久久夜精品va视频免费观看| 日韩一区二区在线视频| 91热精品视频| 欧美日韩在线观看视频小说| 91精品国产九九九久久久亚洲| 日韩美女视频中文字幕| 性欧美在线看片a免费观看| 亚洲欧美制服综合另类| 国产精品视频一区国模私拍| 黑人狂躁日本妞一区二区三区| xxxxx91麻豆| 亚洲一区二区三区sesese| 久久久久久久电影一区| 国产欧美在线观看| 亚洲欧美日韩中文视频| 欧美国产日韩中文字幕在线| 亚洲老头同性xxxxx| 国产精品亚洲欧美导航| 国产成人极品视频| 国产不卡av在线免费观看| 日韩一区二区久久久| 欧美视频一区二区三区…| 国产精品一二三在线| 亚洲国产精品久久精品怡红院| 欧美裸体视频网站| 日韩精品在线免费观看视频| 97在线精品国自产拍中文| 国产日韩在线精品av| 亚洲第一免费播放区| 欧美日韩国产精品一区二区不卡中文| 神马久久桃色视频| 一区二区在线视频播放| 国产玖玖精品视频| 日韩精品极品视频| 永久555www成人免费| 亚洲欧美日韩久久久久久| 在线观看视频99| 国产欧美日韩精品丝袜高跟鞋| 国产精品亚洲精品| 国产成人精品a视频一区www| 午夜精品久久久久久久男人的天堂| 精品在线观看国产|