在unity開發(fā)中灌旧,觸屏手勢在我看來是以手指ID號(hào)(手指的身份)以及手指狀態(tài)為標(biāo)準(zhǔn)界定判斷手勢的類型的动猬;一些插件感覺和iOS中蘋果封裝的差不多阶剑,因此就UIGestureRecognizer這個(gè)類關(guān)于API使用進(jìn)行一下初步探索普筹。冒版。筐乳。
一歌殃、UIGestureRecognizer
-
給手勢添加多個(gè)Target; 觸發(fā)后執(zhí)行順序按照添加的順序執(zhí)行
-
獲取手指相對(duì)于某一個(gè)view位置
第二個(gè)方法中touchIndex是手指的序號(hào)(比如手勢是兩個(gè)手指觸發(fā),手指接觸屏幕肯定有先后蝙云,第一個(gè)接觸的系統(tǒng)內(nèi)部自動(dòng)給其標(biāo)為第0個(gè)氓皱,第二個(gè)手指給其標(biāo)記為第1個(gè))
-
不太明白的東西
-
UIGestureRecognizer.state
介紹
-
UIGestureRecognizerStatePossible
尚未識(shí)別是何種手勢操作(但可能已經(jīng)觸發(fā)了觸摸事件),默認(rèn)狀態(tài) -
UIGestureRecognizerStateCancelled
這個(gè)狀態(tài)可以在手勢被觸發(fā)之后:1.當(dāng)前手指沒發(fā)生變化勃刨,又增加了手指(這個(gè)手勢沒有結(jié)束的時(shí)候又多了手勢進(jìn)來)2.結(jié)束之前設(shè)置手勢enable
屬性為NO觸發(fā)
-
UIGestureRecognizerStateFailed
不知道怎么觸發(fā)這個(gè)狀態(tài)波材,但是利用方法requireGestureRecognizerToFail:
可以保證在other Gesture failed狀態(tài)下this Gesture才可以觸發(fā),代理方法gestureRecognizerShouldBegin:
亦與之相關(guān)
-
UIGestureRecognizerStateRecognized
在識(shí)別結(jié)束之后,end狀態(tài)結(jié)束以后身隐,個(gè)人理解為表示這個(gè)手勢結(jié)束
+示例: 對(duì)于離散型手勢 UITapGestureRecgnizer 要么被識(shí)別廷区,要么失敗,點(diǎn)按(假設(shè)點(diǎn)按次數(shù)設(shè)置為1贾铝,并且沒有添加長按手勢)下去一次不松開則此時(shí)什么也不會(huì)發(fā)生隙轻,松開手指立即識(shí)別并調(diào)用操作事件,并且狀態(tài)為3(已完成)垢揩。但是連續(xù)型手勢要復(fù)雜一些玖绿,就拿旋轉(zhuǎn)手勢來說,如果兩個(gè)手指點(diǎn)下去不做任何操作叁巨,此時(shí)并不能識(shí)別手勢(因?yàn)槲覀冞€沒旋轉(zhuǎn))但是其實(shí)已經(jīng)觸發(fā)了觸摸開始事件斑匪,此時(shí)處于狀態(tài)0;如果此時(shí)旋轉(zhuǎn)會(huì)被識(shí)別锋勺,也就會(huì)調(diào)用對(duì)應(yīng)的操作事件蚀瘸,同時(shí)狀態(tài)變成1(手勢開始),但是狀態(tài)1只有一瞬間庶橱;緊接著狀態(tài)變?yōu)?(因?yàn)槲覀兊男D(zhuǎn)需要持續(xù)一會(huì))苍姜,并且重復(fù)調(diào)用操作事件(如果在事件中打印狀態(tài)會(huì)重復(fù)打印2);松開手指悬包,此時(shí)狀態(tài)變?yōu)?衙猪,并調(diào)用1次操作事件。
-
UIGestureRecognizer.delegate
介紹
-
gestureRecognizerShouldBegin:
在手勢想要從UIGestureRecognizerStatePossible
狀態(tài)變化的時(shí)候調(diào)用,返回NO則表示手勢狀態(tài)是UIGestureRecognizerStateFailed
-
gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer:
在手勢沖突時(shí)候調(diào)用垫释,默認(rèn)返回NO表示默認(rèn)不能同時(shí)識(shí)別兩個(gè)手勢 -
gestureRecognizer: shouldRequireFailureOfGestureRecognizer:
每次嘗試識(shí)別手勢都會(huì)調(diào)用丝格,一般只會(huì)在手勢沖突時(shí)候,比如同時(shí)添加輕擊手勢和長按手勢棵譬,輕擊手勢設(shè)置代理显蝌,在區(qū)分是輕擊手勢或者長按手勢還沒有確定結(jié)果的時(shí)候調(diào)用,而不設(shè)置輕擊手勢代理而設(shè)置長按代理的時(shí)候就不會(huì)調(diào)用 -
gestureRecognizer: shouldBeRequiredToFailByGestureRecognizer:
調(diào)用時(shí)機(jī)同上 -
gestureRecognizer: shouldReceiveTouch:
在上面兩個(gè)方法之前調(diào)用 -
gestureRecognizer: shouldReceivePress:
同上
二订咸、UIGestureRecognizer子類
UIGestureRecognizer子類有:
UITapGestureRecognizer
(輕擊)
UILongPressGestureRecognizer
(長按)
?UISwipeGestureRecognizer
(輕掃)
UIPanGestureRecognizer
(拖動(dòng))
UIPinchGestureRecognizer
(捏合)
UIRotationGestureRecognizer
(旋轉(zhuǎn))
UIScreenEdgePanGestureRecognizer
(屏幕邊緣手勢繼承于pan手勢)
輕擊UITapGestureRecognizer
- 可以通過修改
numberOfTapsRequired
(敲擊次數(shù)默認(rèn)1)和numberOfTouchesRequired
(手指個(gè)數(shù)默認(rèn)1)兩個(gè)參數(shù)進(jìn)行輕擊手勢的配置,不配置按默認(rèn).
長按UILongPressGestureRecognizer
- 長按手勢
numberOfTapsRequired
手指敲擊次數(shù)默認(rèn)為0曼尊,如果設(shè)置1需要先輕吉再長按才能觸發(fā)
- 長按手勢可以通過
numberOfTouchesRequired
(手指個(gè)數(shù))minimumPressDuration
(最小按壓時(shí)間)allowableMovement
(允許移動(dòng)像素單位范圍:在識(shí)別手勢期間移動(dòng)超過范圍手勢識(shí)別失效)進(jìn)行配置
輕掃?UISwipeGestureRecognizer
- 可以配置的有
numberOfTouchesRequired
(手指的個(gè)數(shù)默認(rèn)1)direction
(輕掃的方向:上下左右;默認(rèn)右表示手指在屏幕從左到右滑動(dòng)和邊緣滑動(dòng)手勢方向不同)
拖動(dòng)UIPanGestureRecognizer
-
minimumNumberOfTouches
最少可以識(shí)別到的手指數(shù)量>=1maximumNumberOfTouches
最多可以識(shí)別到的手指數(shù)量 -
- (CGPoint)translationInView:(nullable UIView *)view;
相對(duì)于began時(shí)候手指位置的偏移量 -
- (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view;
作用用于重新定位手指 偏移量的計(jì)算 -
- (CGPoint)velocityInView:(nullable UIView *)view;
手指移動(dòng)速度
//拖動(dòng)觸發(fā)后調(diào)用
- (void)panGes:(UIPanGestureRecognizer *)ges{
if (ges.state == UIGestureRecognizerStateChanged) {
//注意這個(gè)方法獲取到的偏移量是相對(duì)于開始識(shí)別到時(shí)候手指的位置并不會(huì)實(shí)時(shí)更新需要再調(diào)用setTranslation: inView:
CGPoint p = [ges translationInView:self.redView];
[ges setTranslation:CGPointZero inView:self.redView];
self.redView.frame = CGRectMake(self.redView.frame.origin.x + p.x, self.redView.frame.origin.y + p.y, self.redView.frame.size.width, self.redView.frame.size.height);
}
}
捏合UIPinchGestureRecognizer
- scale表示形變量;velocity只讀 表示單位時(shí)間scale改變的速度
//捏合觸發(fā)后調(diào)用
- (void)pinchAction:(UIPinchGestureRecognizer *)ges{
if (ges.state == UIGestureRecognizerStateChanged) {
self.redView.transform = CGAffineTransformMakeScale(ges.scale, ges.scale);
}
if(ges.state == UIGestureRecognizerStateEnded)
{
[UIView animateWithDuration:0.5 animations:^{
self.redView.transform = CGAffineTransformIdentity;//取消一切形變
}];
}
}
旋轉(zhuǎn)UIRotationGestureRecognizer
//旋轉(zhuǎn)觸發(fā)后調(diào)用
- (void)rotaAction:(UIRotationGestureRecognizer *)ges{
if (ges.state==UIGestureRecognizerStateChanged)
{
self.redView.transform=CGAffineTransformMakeRotation(ges.rotation);
}
if(ges.state==UIGestureRecognizerStateEnded)
{
[UIView animateWithDuration:1 animations:^{
self.redView.transform=CGAffineTransformIdentity;//取消形變
}];
}
}
屏幕邊緣手勢UIScreenEdgePanGestureRecognizer
- 繼承于pan手勢脏嚷,一般用于左側(cè)滑動(dòng)返回骆撇。吐槽一下,給自定義View添加之后父叙,我發(fā)現(xiàn)觸發(fā)特別難神郊,貌似只有
UIRectEdgeLeft
和UIRectEdgeRight
觸發(fā)情況會(huì)好一點(diǎn),不知道為啥趾唱。涌乳。。甜癞。我絕對(duì)沒有說fuck
三夕晓、自定義手勢
好吧,我觸發(fā)不了系統(tǒng)屏幕邊緣手勢我自己寫一個(gè)行了吧悠咱。蒸辆。。乔煞。自定義手勢需要注意幾點(diǎn):
- 繼承自
UIGestureRecognizer
- .m文件包含頭文件
#import <UIKit/UIGestureRecognizerSubclass.h>
- 手勢判斷之后設(shè)置
self.state = UIGestureRecognizerStateEnded;
就會(huì)自動(dòng)調(diào)用對(duì)應(yīng)方法了
WPGesture.h
#import <UIKit/UIKit.h>
@interface WPGesture : UIGestureRecognizer
//需要幾根手指
@property(nonatomic, assign)NSUInteger wpNumberOfTouchesRequired;//默認(rèn)1
//需要幾次點(diǎn)擊
@property(nonatomic, assign)NSUInteger wpNumberOfTapsRequired;//默認(rèn)0
//哪一邊
@property (readwrite, nonatomic, assign) UIRectEdge wpEdges;//默認(rèn)UIRectEdgeAll
@end
WPGesture.m
#import "WPGesture.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface WPGesture()
@property(nonatomic, assign)BOOL isCorrected;
@end
@implementation WPGesture
//在began里面識(shí)別手勢是否正確: 幾根手指 幾次點(diǎn)擊 哪一邊 此方法左右:作為手勢識(shí)別器
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
//0.判斷手指的tapCount 是否在move里面給出移動(dòng)初始點(diǎn)
for (UITouch * tou in allTouches) {
if(tou.tapCount != (self.wpNumberOfTapsRequired + 1)){
//不符合的話直接return 不再繼續(xù)判斷
return;
}
}
//1.判斷手指個(gè)數(shù)是否符合
if(allTouches.count != self.wpNumberOfTouchesRequired){
//忽略不正確手指 防止干擾到識(shí)別
for (UITouch * tou in allTouches) {
[self ignoreTouch:tou forEvent:event];
}
return;
}
//2.手指個(gè)數(shù)滿足情況下 判斷手指位置是否滿足條件
//用臨時(shí)變量topM等接收 防止屏幕旋轉(zhuǎn)出現(xiàn)
CGFloat topM = self.view.bounds.size.height *0.25;//滿足點(diǎn)要小于top
CGFloat butM = self.view.bounds.size.height *0.75;//滿足點(diǎn)要大于but
CGFloat lefM = self.view.bounds.size.width *0.25;//滿足點(diǎn)要小于lef
CGFloat rigM = self.view.bounds.size.width *0.75;//滿足點(diǎn)要大于rig
if (topM >= 100) {
topM = 100;
butM = self.view.bounds.size.height - 100;
}
if (lefM >= 100) {
lefM = 100;
rigM = self.view.bounds.size.width - 100;
}
// 判斷手指位置是否滿足條件
for (UITouch * tou in allTouches) {
if (!self.view) {
return;
}//貌似能觸發(fā)began就肯定有view
CGPoint touchP = [tou locationInView:self.view];//手指位置
if (self.wpEdges == UIRectEdgeNone) {
return;//UIRectEdgeNone什么也不做
}
if (self.wpEdges == UIRectEdgeTop) {
if (touchP.y > topM) {
[self ignoreTouch:tou forEvent:event];
return;
}
}
if (self.wpEdges == UIRectEdgeBottom) {
if (touchP.y < butM) {
[self ignoreTouch:tou forEvent:event];
return;
}
}
if (self.wpEdges == UIRectEdgeLeft) {
if (touchP.x > lefM) {
[self ignoreTouch:tou forEvent:event];
return;
}
}
if (self.wpEdges == UIRectEdgeRight) {
if (touchP.x < rigM) {
[self ignoreTouch:tou forEvent:event];
return;
}
}
if (self.wpEdges == UIRectEdgeAll) {
if (touchP.y > topM && touchP.y < butM && touchP.x > lefM && touchP.x < rigM) {
[self ignoreTouch:tou forEvent:event];
return;
}
}
}
self.isCorrected = YES;//識(shí)別正確,當(dāng)前狀態(tài)UIGestureRecognizerStatePossible
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
if (!self.isCorrected) {
//不滿足began的情況 直接返回
return;
}
//識(shí)別正確 移動(dòng)既是began
self.state = UIGestureRecognizerStateBegan;//自動(dòng)內(nèi)部會(huì)自動(dòng)改變狀態(tài)為move
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if(self.isCorrected){
self.state = UIGestureRecognizerStateEnded;
self.state = UIGestureRecognizerStateRecognized;
[self reset];
}
}
#pragma mark - 重寫方法
- (void)reset{
[super reset];
self.isCorrected = NO;
}
//沒有end狀態(tài) 又識(shí)別到其他手勢的時(shí)候 多了手指出來
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer{
BOOL res = [super canPreventGestureRecognizer:preventedGestureRecognizer];
self.state = UIGestureRecognizerStateCancelled;
[self reset];
return res;
}
//第一次識(shí)別 touchBegan之后調(diào)用
- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
BOOL res = [super shouldRequireFailureOfGestureRecognizer:otherGestureRecognizer];
return res;
}
#pragma mark - 默認(rèn)值設(shè)置
//重寫init 設(shè)置默認(rèn)值
- (instancetype)init{
if(self = [super init]){
self.wpEdges = UIRectEdgeAll;
self.wpNumberOfTapsRequired = 0;
self.wpNumberOfTouchesRequired = 1;
self.isCorrected = NO;
}
return self;
}
- (instancetype)initWithTarget:(id)target action:(SEL)action{
if (self = [super initWithTarget:target action:action]) {
self.wpEdges = UIRectEdgeAll;
self.wpNumberOfTapsRequired = 0;
self.wpNumberOfTouchesRequired = 1;
self.isCorrected = NO;
}
return self;
}
@end