iOS開發中的手勢體系——UIGestureRecognizer分析及其子類的使用

iOS開發中的手勢體系——UIGestureRecognizer分析及其子類的使用

1、引言

        在iOS系統中,手勢是進行用戶交互的重要方式,經過UIGestureRecognizer類,咱們能夠輕鬆的建立出各類手勢應用於app中。關於UIGestureRecognizer類,是對iOS中的事件傳遞機制面向應用的封裝,將手勢消息的傳遞抽象爲了對象。有關消息傳遞的一些討論,在前面的博客中有提到:併發

iOS事件響應控制:http://my.oschina.net/u/2340880/blog/396161app

2、手勢的抽象類——UIGestureRecognizer

        UIGestureRecognizer將一些和手勢操做相關的方法抽象了出來,但它自己並不實現什麼手勢,所以,在開發中,咱們通常不會直接使用UIGestureRecognizer的對象,而是經過其子類進行實例化,iOS系統給咱們提供了許多用於咱們實例的子類,這些咱們後面再說,咱們先來看一下,UIGestureRecognizer中抽象出了哪些方法。ui

一、統一的初始化方法

        UIGestureRecognizer類爲其子類準備好了一個統一的初始化方法,不管什麼樣的手勢動做,其執行的結果都是同樣的:觸發一個方法,可使用下面的方法進行統一的初始化:atom

- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action;

固然,若是咱們使用alloc-init的方式,也是能夠的,下面的方法能夠爲手勢添加觸發的selector:spa

- (void)addTarget:(id)target action:(SEL)action;

與之相對應的,咱們也能夠將一個selector從其手勢對象上移除:.net

- (void)removeTarget:(nullable id)target action:(nullable SEL)action;

上面兩個方法是十分有意思的,由於addTarget方式的存在,iOS系統容許一個手勢對象能夠添加多個selector觸發方法,而且觸發的時候,全部添加的selector都會被執行,咱們以點擊手勢示例以下:代理

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
     UITapGestureRecognizer * ges = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];
    [ges addTarget:self action:@selector(haha)];
     [self.view addGestureRecognizer:ges];
}
-(void)click:(UIGestureRecognizer *)ges{
    
    NSLog(@"第一個手勢的觸發方法");
    
}
-(void)haha{
    NSLog(@"haha");
}

運行後點擊屏幕,打印以下,說明兩個方法都觸發了:code

二、手勢狀態

        UIgestureRecognizer類中有以下一個屬性,裏面枚舉了一些手勢的當前狀態:對象

@property(nonatomic,readonly) UIGestureRecognizerState state;

枚舉值以下:blog

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,   // 默認的狀態,這個時候的手勢並無具體的情形狀態
    UIGestureRecognizerStateBegan,      // 手勢開始被識別的狀態
    UIGestureRecognizerStateChanged,    // 手勢識別發生改變的狀態
    UIGestureRecognizerStateEnded,      // 手勢識別結束,將會執行觸發的方法
    UIGestureRecognizerStateCancelled,  // 手勢識別取消
    UIGestureRecognizerStateFailed,     // 識別失敗,方法將不會被調用
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded 
};

三、經常使用屬性和方法

//設置代理,具體的協議後面會說
@property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> delegate; 
//設置手勢是否有效
@property(nonatomic, getter=isEnabled) BOOL enabled;
//獲取手勢所在的view
@property(nullable, nonatomic,readonly) UIView *view; 
//獲取觸發觸摸的點
- (CGPoint)locationInView:(nullable UIView*)view; 
//設置觸摸點數
- (NSUInteger)numberOfTouches; 
//獲取某一個觸摸點的觸摸位置
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;

下面的幾個BOOL值的屬性,對於手勢觸發的控制也十分重要:

(1)
@property(nonatomic) BOOL cancelsTouchesInView;

上面的屬性默認爲YES,當這個屬性設置爲YES時,若是識別到了手勢,系統將會發送touchesCancelled:withEvent:消息在其時間傳遞鏈上,終止觸摸事件的傳遞,設置爲NO,則不會終止事件的傳遞,舉個例子來講,可能會更加清楚一些以下:

- (void)viewDidLoad {
    [super viewDidLoad];
     UIPanGestureRecognizer * ges = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];;
    [self.view addGestureRecognizer:ges];
    ges.cancelsTouchesInView=NO;
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSLog(@"123");
}
-(void)click:(UIGestureRecognizer *)ges{
    NSLog(@"第一個手勢的觸發方法");
}

上面咱們使用了拖拽手勢和touchesMoved兩個觸發方式,當咱們把cancelTouchesInView設置爲NO時,在屏幕上滑動,會發現兩種方式都在觸發,打印以下:

若是咱們將cancelTouchesInView改成YES,當手勢觸發時,將取消觸摸消息的觸發:

(2)
@property(nonatomic) BOOL delaysTouchesBegan;

經過上面的例子,咱們知道,在一個手勢觸發以前,是會一併發消息給事件傳遞鏈的,delaysTouchesBgan屬性用於控制這個消息的傳遞時機,默認這個屬性爲NO,此時在觸摸開始的時候,就會發消息給事件傳遞鏈,若是咱們設置爲YES,在觸摸沒有被識別失敗前,都不會給事件傳遞鏈發送消息。

(3)
@property(nonatomic) BOOL delaysTouchesEnded;

這個屬性設置手勢識別結束後,是馬上發送touchesEnded消息到事件傳遞鏈或者等待一個很短的時間後,若是沒有接收到新的手勢識別任務,再發送。

四、手勢間的互斥處理

        有一點須要注意,同一個View上是能夠添加多個手勢對象的,默認這個手勢是互斥的,一個手勢觸發了就會默認屏蔽其餘類似的手勢動做,例如:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
     UITapGestureRecognizer * ges = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];;
    
    //view.backgroundColor = [UIColor redColor];
   
    //ges.delegate=self;
    [self.view addGestureRecognizer:ges];
    
    UITapGestureRecognizer * ges2 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click1:)];
//    ges2.delegate=self;
        [self.view addGestureRecognizer:ges2];
}


-(void)click:(UIGestureRecognizer *)ges{
    
    NSLog(@"第一個手勢的觸發方法");
    
}
-(void)click1:(UIGestureRecognizer *)ges1{
    NSLog(@"第二個手勢的觸發方法");
    
    
}

咱們添加的兩個手勢都是單機手勢,會產生衝突,觸發是很隨機的,若是咱們想設置一下當手勢互斥時要優先觸發的手勢,可使用以下的方法:

- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;

這個方法中第一個參數是須要時效的手勢,第二個是生效的手勢。

3、UIGestureRecognizerDelegate

        前面咱們提到過關於手勢對象的協議代理,經過代理的回調,咱們能夠進行自定義手勢,也能夠處理一些複雜的手勢關係,其中方法以下:

//手指觸摸屏幕後回調的方法,返回NO則再也不進行手勢識別,方法觸發等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
//開始進行手勢識別時調用的方法,返回NO則結束,再也不觸發手勢
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
//是否支持多時候觸發,返回YES,則能夠多個手勢一塊兒觸發方法,返回NO則爲互斥
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
//下面這個兩個方法也是用來控制手勢的互斥執行的
//這個方法返回YES,第一個手勢和第二個互斥時,第一個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
//這個方法返回YES,第一個和第二個互斥時,第二個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

4、點擊手勢——UITapGestureRecognizer

        點擊手勢十分簡單,支持單擊和屢次點擊,在咱們手指觸摸屏幕並擡起手指時會進行觸發,其中有以下兩個屬性咱們能夠進行設置:

//設置點擊次數,默認爲單擊
@property (nonatomic) NSUInteger  numberOfTapsRequired; 
//設置同時點擊的手指數
@property (nonatomic) NSUInteger  numberOfTouchesRequired;

5、捏合手勢——UIPinchGestureRecognizer

        捏合手勢是當咱們雙指捏合和擴張會觸發動做的手勢,咱們能夠設置的屬性以下:

//設置縮放比例
@property (nonatomic)          CGFloat scale; 
//設置捏合速度
@property (nonatomic,readonly) CGFloat velocity;

6、拖拽手勢——UIPanGestureRecognzer

        當咱們點中視圖進行慢速拖拽時會觸發拖拽手勢的方法。

//設置觸發拖拽的最少觸摸點,默認爲1
@property (nonatomic)          NSUInteger minimumNumberOfTouches; 
//設置觸發拖拽的最多觸摸點
@property (nonatomic)          NSUInteger maximumNumberOfTouches;  
//獲取當前位置
- (CGPoint)translationInView:(nullable UIView *)view;            
//設置當前位置
- (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view;
//設置拖拽速度
- (CGPoint)velocityInView:(nullable UIView *)view;

7、滑動手勢——UISwipeGestureRecognizer

        滑動手勢和拖拽手勢的不一樣之處在於滑動手勢更快,拖拽比較慢。

//設置觸發滑動手勢的觸摸點數
@property(nonatomic) NSUInteger                        numberOfTouchesRequired; 
//設置滑動方向
@property(nonatomic) UISwipeGestureRecognizerDirection direction;  
//枚舉以下
typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {
    UISwipeGestureRecognizerDirectionRight = 1 << 0,
    UISwipeGestureRecognizerDirectionLeft  = 1 << 1,
    UISwipeGestureRecognizerDirectionUp    = 1 << 2,
    UISwipeGestureRecognizerDirectionDown  = 1 << 3
};

8、旋轉手勢——UIRotationGestureRecognizer

        進行旋轉動做時觸發手勢方法。

//設置旋轉角度
@property (nonatomic)          CGFloat rotation;
//設置旋轉速度 
@property (nonatomic,readonly) CGFloat velocity;

 9、長按手勢——UILongPressGestureRecognizer

        進行長按的時候觸發的手勢方法。

//設置觸發前的點擊次數
@property (nonatomic) NSUInteger numberOfTapsRequired;    
//設置觸發的觸摸點數
@property (nonatomic) NSUInteger numberOfTouchesRequired; 
//設置最短的長按時間
@property (nonatomic) CFTimeInterval minimumPressDuration; 
//設置在按觸時時容許移動的最大距離 默認爲10像素
@property (nonatomic) CGFloat allowableMovement;

 

專一技術,熱愛生活,交流技術,也作朋友。

——琿少 QQ羣:203317592

相關文章
相關標籤/搜索