iOS只有繼承UIResponder類的對象才能處理事件。(UIView,UIViewController,UIApplication...)app
UIResponder中定義了上述幾類事件函數
:fa-hand-o-down:一根或多根手指開始觸摸屏幕時開始執行ui
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
:fa-hand-o-down:一根或多根手指在屏幕上移動時執行,:tw-2757:移動過程當中會屢次調用atom
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
:fa-hand-o-down:一個或多根手指觸摸結束離開屏幕時執行代理
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
:fa-hand-o-down:觸摸意外終止時執行(如:觸摸時打入電話)code
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
:fa-plus-square:iOS9.1新加方法orm
- (void)touchesEstimatedPropertiesUpdated:(NSSet * _Nonnull)touches(IOS9.1)
能夠從UITouch對象中,獲取一下觸摸信息:對象
//取得一個觸摸對象,(對於多點觸摸可能有多個對象) UITouch *touch = [touches anyObject];繼承
touch.window : 觸摸時所在的窗口three
touch.view : 觸摸時所在的視圖
touch.tapCount : 短期內的點擊次數
touch.timestamp : 觸摸產生或變化的時間戳
touch.phase : 觸摸週期內的各個狀態
locationInView: 方法:取得在指定視圖的位置
previousLocationInView : 方法:取得移動前的一個位置
...
......
:fa-hand-o-down:按壓物理按鈕時開始執行
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event;
:fa-hand-o-down:按壓物理按鈕時開始執行並移動時開始執行,:tw-2757:移動過程當中會屢次調用
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event;
:fa-hand-o-down:按壓物理按鈕結束,離開屏幕時開始執行
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event;
:fa-hand-o-down:按壓意外終止時執行(如:按壓時打入電話)
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event;
**前提:**監聽運動事件時,監聽對象必須是第一響應者(UIViewController,UIApplication無此要求)
①-(BOOL)canBecomeFirstResponder{ return YES; } ②視圖顯示時,註冊爲第一響應者 -(void)viewWillAppear:(BOOL)animated{ [view becomeFirstResponder]; } ③視圖再也不顯示時,註銷第一響應者 -(void)viewWillDisappear:(BOOL)animated{ [view resignFirstResponder]; }
API:
:fa-hand-o-down:運動開始時執行
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event ;
:fa-hand-o-down:運動結束時執行
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event ;
:fa-hand-o-down:運動意外取消時執行
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
主要說耳機線控
遠程控制事件通常都添加到UIApplication,UIViewController中,不會直接添加到UI控件
前提:
①啓動遠程事件接受 [[UIApplication shareApplication] beginReceivingRemoteControlEvents]; ②UI控件必須爲第一響應者(UIViewController UIApplication對象監聽無此要求) [view becomeFirstResponder]; ③應用程序必須是當前音頻的控制者:通知欄中的音頻播放程序必須是本身開發的程序
事件類型:
搖晃事件+(遠程控制:線控)音頻播放 typedef NS_ENUM(NSInteger, UIEventSubtype) { UIEventSubtypeNone = 0, UIEventSubtypeMotionShake = 1, //>>搖晃(運動)事件 UIEventSubtypeRemoteControlPlay = 100, //>>播放:耳機線控中間按鈕按一下 UIEventSubtypeRemoteControlPause = 101, //>>暫停 UIEventSubtypeRemoteControlStop = 102, //>>中止 UIEventSubtypeRemoteControlTogglePlayPause = 103, //>>播放暫停切換:耳機線控中間按鈕按一下 UIEventSubtypeRemoteControlNextTrack = 104, //>>下一曲:耳機線控中間按鈕按兩下 UIEventSubtypeRemoteControlPreviousTrack = 105, //>>上一曲:耳機線控中間按鈕按三下 UIEventSubtypeRemoteControlBeginSeekingBackward = 106, //>>快退開始:耳機線控中間按鈕按三下不要鬆開 UIEventSubtypeRemoteControlEndSeekingBackward = 107, //>>快退結束:耳機線控中間按鈕按三下到了快退位置鬆開 UIEventSubtypeRemoteControlBeginSeekingForward = 108, //>>快進開始:耳機線控中間按鈕按兩下不要鬆開 UIEventSubtypeRemoteControlEndSeekingForward = 109, //>>快進結束:耳機線控中間按鈕按兩下到了快進位置鬆開 };
事件觸發函數
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
離散手勢:一旦識別沒法取消,且只會觸發一次手勢操做事件
連續手勢:識別後能夠取消, 會屢次觸發手勢操做事件
UIGestureRecognizer |-屬性 | |-@property(nonatomic, readonly) UIGestureRecognizerState state 手勢狀態 | |-@property(nonatomic, getter=isEnabled) BOOL enabled 手勢是否可用 | |-@property(nullable, nonatomic,readonly) UIView *view 觸發手勢的視圖 | |-@property(nonatomic) BOOL delaysTouchesBegan //default:NO | | |-YES:成功識別手勢,則不執行觸摸開始事件,失敗則執行 | | |-NO :無論是否識別手勢,都執行觸摸開始事件 | |-@property(nonatomic) BOOL delaysTouchesEnded; |—————————————————————————————————————————————————————————————————— |- 方法 | |-(void)addTarget:(id)target action:(SEL)action; //添加觸摸執行事件 | |-(void)removeTarget:(id)target action:(SEL)action;//移除觸摸執行事件 | |-(NSUInteger)numberOfTouches; //同時觸摸的手指數 | |-(CGPoint)locationInView:(UIView*)view; //單點觸摸在指定視圖中的相對位置 | |-(CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView*)view; //多點觸摸時觸摸點在視圖中的相對位置 | |-(void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer; //手勢失敗時,執行另外一個手勢 |—————————————————————————————————————————————————————————————————— |- 代理方法:UIGestureRecognizerDelegate | |-(待更新) | | |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |-六種子類手勢 | |-UITapGestureRecognizer -點擊手勢(離散) | | |-@property (nonatomic) NSUInteger numberOfTapsRequired //點擊次數:1 | | |-@property (nonatomic) NSUInteger numberOfTouchesRequired //點擊手指數:1 | |———————————————————————————————————————————————————————————— | |-UILongPressGestureRecognizer -長按手勢 | | |-@property (nonatomic) NSUInteger numberOfTapsRequired:1 | | |-@property (nonatomic) NSUInteger numberOfTouchesRequired:1 | | |-@property (nonatomic) CFTimeInterval minimumPressDuration //設置長按時間 默認:0.5 | | |-@property (nonatomic) CGFloat allowableMovement //默認容許移動10個像素 | |———————————————————————————————————————————————————————————— | |-UIPinchGestureRecognizer -捏合手勢 | | |-@property (nonatomic) CGFloat scale //紀錄縮放比例 | | |-@property (nonatomic,readonly) CGFloat velocity//紀錄縮放速度 | |———————————————————————————————————————————————————————————— | |-UIPanGestureRecognizer -拖動手勢 | | |-@property (nonatomic) NSUInteger minimumNumberOfTouches //手勢所需最小手指數 | | |-@property (nonatomic) NSUInteger maximumNumberOfTouches //手勢所需最大手指數 | | |-(CGPoint)translationInView:(UIView *)view //移動距離 | | |-(CGPoint)velocityInView:(UIView *)view //移動速度 | |———————————————————————————————————————————————————————————— | |-UISwipeGestureRecognizer -輕掃手勢:支持四個方向 | | |-@property(nonatomic) NSUInteger numberOfTouchesRequired //:1 | | |-@property(nonatomic) UISwipeGestureRecognizerDirection direction | |———————————————————————————————————————————————————————————— | |-UIRotationGestureRecognizer -旋轉手勢 | | |-@property (nonatomic) CGFloat rotation //紀錄旋轉角度 | | |-@property (nonatomic,readonly) CGFloat velocity //紀錄旋轉速度
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) { UIGestureRecognizerStatePossible, //>>默認,還沒有識別 UIGestureRecognizerStateBegan, //>>手勢開始,已被識別(瞬間) UIGestureRecognizerStateChanged, //>>手勢狀態發生變化 UIGestureRecognizerStateEnded, //>>手勢識別操做完成(已鬆開手指) UIGestureRecognizerStateCancelled, //>>手勢被取消,恢復默認 UIGestureRecognizerStateFailed, //>>手勢識別失敗,恢復默認 UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
以旋轉爲例子-分爲如下幾個步驟:
:tw-26a0:對於非交互UI控件(UIImageView)須要將userInteractionEnabled = NO;
:tw-26a0:輕掃手勢雖然是連續手勢,但:操做事件智慧在識別結束時調用一次。有必要進行狀態判斷
:one:建立對應的手勢對象
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationImage:)];
:two:設置手勢識別屬性(可選) - :three:附加手勢到指定對象
[_imageView addGestureRecognizer:rotationGesture];
:four:編寫手勢操做方法
//旋轉圖片 -(void)rotationImage:(UIRotationGestureRecognizer *)gesture{ if (gesture.state == UIGestureRecognizerStateChanged) { // 旋轉手勢中rotation記錄了旋轉弧度 _imageView.transform = CGAffineTransformMakeRotation(gesture.rotation); }else if (gesture.state == UIGestureRecognizerStateEnded){ [UIView animateWithDuration:0.8 animations:^{ //取消形變 _imageView.transform = CGAffineTransformIdentity; }]; } }
拖動手勢的操做事件是在手勢的開始狀態(狀態1)被識別執行
輕掃手勢的操做事件是在手勢的結束狀態(狀態3)被識別執行
所以輕掃手勢沒有被正確識別
總結: iOS中手勢A的識別部分是手勢B的子部分時,默認A先被識別,B就沒法識別了 利用:
//手勢失敗時,執行另外一個手勢 - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
經過該方法:指定拖動手勢執行的前提爲 輕掃手勢失敗。
這樣系統會優先執行輕掃手勢,若是不是輕掃手勢,就會執行拖動 例:
//解決拖動和輕掃的衝突 [panGesture requiredGestureRecognizerToFail : swipeGestureToRight]; //解決拖動和長按手勢的衝突 [longGesture requiredGestureRecognizerToFail : panGesture];
事件觸發事件是根據響應鏈傳播的,上層觸摸事件執行後就不會向下傳播。
手勢也是相似:先識別的手勢會阻斷手勢識別操做繼續傳播
:fa-question-circle:如何讓兩個有層次關係並都添加了手勢的空間正確識別手勢?
:fa-check-square:經過代理UIGestureRecognizerDelegate
vcViewGesture.delegate = self; [vc.view addGestureRecognizer : vcViewGesture]; //默認返回NO:阻止手勢向下傳播 //YES :容許向下傳播 //控制只有在UIImageView中才能向下傳播 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ if([otherGestureRecognizer.view isKindOfClass:[UIImageView class]]){ return YES; } return NO; }