在用戶使用app過程中,會產生各種各樣的事件
iOS中的事件可以分為3大類型
在iOS中不是任何對象都能處理事件,只有繼承了UIResponder的對象才能接收并處理事件。我們稱之為“響應者對象”
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
一根或者多根手指開始觸摸view,系統會自動調用view的下面方法
一根或者多根手指在view上移動,系統會自動調用view的下面方法(隨著手指的移動,會持續調用該方法)
一根或者多根手指離開view,系統會自動調用view的下面方法
觸摸結束前,某個系統事件(例如電話呼入)會打斷觸摸過程,系統會自動調用view的下面方法
提示:touches中存放的都是UITouch對象
UITouch的作用
保存著跟手指相關的信息,比如觸摸的位置、時間、階段
當手指移動時,系統會更新同一個UITouch對象,使之能夠一直保存該手指在的觸摸位置
當手指離開屏幕時,系統會銷毀相應的UITouch對象
提示:iphone開發中,要避免使用雙擊事件!
觸摸產生時所處的窗口
觸摸產生時所處的視圖
短時間內點按屏幕的次數,可以根據tapCount判斷單擊、雙擊或更多的點擊
記錄了觸摸事件產生或變化時的時間,單位是秒
當前觸摸事件所處的狀態
- (CGPoint)locationInView:(UIView *)view;*返回值表示觸摸在view上的位置*這里返回的位置是針對view的坐標系的(以view的左上角為原點(0, 0))*調用時傳入的view參數為nil的話,返回的是觸摸點在UIWindow的位置- (CGPoint)previousLocationInView:(UIView *)view;該方法記錄了前一個觸摸點的位置
1、事件類型@property(nonatomic,readonly) UIEventType type;@property(nonatomic,readonly) UIEventSubtype subtype;2、事件產生的時間@property(nonatomic,readonly) NSTimeInterval timestamp;3、UIEvent還提供了相應的方法可以獲得在某個view上面的觸摸對象(UITouch)
觸摸開始:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event觸摸移動:- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event觸摸結束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event觸摸取消(可能會經歷:比如有電話打進來了):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
4個觸摸事件處理方法中,都有NSSet touches和UIEvent event兩個參數
一次完整的觸摸過程中,只會產生一個事件對象,4個觸摸方法都是同一個event參數
如果兩根手指同時觸摸一個view,那么view只會調用一次touchesBegan:withEvent:方法,touches參數中裝著2個UITouch對象
如果這兩根手指一前一后分開觸摸同一個view,那么view會分別調用2次touchesBegan:withEvent:方法,并且每次調用時的touches參數中只包含一個UITouch對象
根據touches中UITouch的個數可以判斷出是單點觸摸還是多點觸摸
發生觸摸事件后,系統會將該事件加入到一個由UIApplication管理的事件隊列中
UIApplication會從事件隊列中取出最前面的事件,并將事件分發下去以便處理,通常,先發送事件給應用程序的主窗口(keyWindow)
主窗口會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件,這也是整個事件處理過程的第一步
找到合適的視圖控件后,就會調用視圖控件的touches方法來作具體的事件處理
隱藏
透明
提示:UIImageView的userInteractionEnabled默認就是NO,因此UIImageView以及它的子控件默認是不能接收觸摸事件的
如果父控件不能接收觸摸事件,那么子控件就不可能接收到觸摸事件(掌握)
如何找到最合適的控件來處理事件?
兩個重要的方法
// 事件傳遞的時候調用// 什么時候調用:當事件傳遞給控件的時候,就會調用控件的這個方法,去尋找最合適的view// 作用:尋找最合適的view// point:當前的觸摸點,point這個點的坐標系就是方法調用者- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event// 作用:判斷當前這個點在不在方法調用者(控件)上- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
/** hitTest底層實現 */- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ // 1、是否能接收點擊事件 // 如果當前視圖不能進行用戶交互、hidden=YES、alpha<=0.01,則表示當前的view不能接收事件 if (!self.userInteractionEnabled || self.hidden || self.alpha<=0.01) return nil; // 2、點擊的點有沒有在視圖上面 if (![self pointInside:point withEvent:event]) { // 點,不在當前視圖上 return nil; } // 3、反向遍歷子控制器 NSInteger count = self.subviews.count; for (NSInteger i = count-1; i>=0; i--) { UIView *view = self.subviews[i]; // 將當前坐標系point轉化成子控件的point CGPoint childP = [self convertPoint:point toView:view]; UIView *fitView = [view hitTest:childP withEvent:event]; if (fitView) { return fitView; } } // 4、如果都沒有,返回self return self;}
用戶點擊屏幕后產生的一個觸摸事件,經過一系列的傳遞過程后,會找到最合適的視圖控件來處理這個事件
找到最合適的視圖控件后,就會調用控件的touches方法來作具體的事件處理
這些touches方法的默認做法是將事件順著響應者鏈條向上傳遞,將事件交給上一個響應者進行處理
1> 先將事件對象由上往下傳遞(由父控件傳遞給子控件),找到最合適的控件來處理這個事件。
2> 調用最合適控件的touches….方法
3> 如果調用了[super touches….];就會將事件順著響應者鏈條往上傳遞,傳遞給上一個響應者
4> 接著就會調用上一個響應者的touches….方法
如果UIApplication也不能處理該事件或消息,則將其丟棄
代理方法
// 是否允許同時支持多個手勢,默認是不支持多個手勢// 返回yes表示支持多個手勢- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES;}// 是否允許開始觸發手勢- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ return NO;}// 是否允許接收手指的觸摸點- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{ // 獲取當前的觸摸點 CGPoint curP = [touch locationInView:self.imageView]; if (curP.x < self.imageView.bounds.size.width * 0.5) { return NO; }else{ return YES; }}
如果想監聽一個view上面的觸摸事件,之前的做法是
自定義一個view
實現view的touches方法,在方法內部實現具體處理代碼
由于是在view內部的touches方法中監聽觸摸事件,因此默認情況下,無法讓其他外界對象監聽view的觸摸事件
不容易區分用戶的具體手勢行為
iOS 3.2之后,蘋果推出了手勢識別功能(Gesture Recognizer),在觸摸事件處理方面,大大簡化了開發者的開發難度
為了完成手勢識別,必須借助于手勢識別器----UIGestureRecognizer
利用UIGestureRecognizer,能輕松識別用戶在某個view上面做的一些常見手勢
- (void)setUpPinch{ UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)]; [self.image addGestureRecognizer:pinch];}- (void)pinch:(UIPinchGestureRecognizer *)pinch{ NSLog(@"%f", pinch.scale); self.image.transform = CGAffineTransformScale(self.image.transform, pinch.scale, pinch.scale); // 復位 pinch.scale = 1;}
- (void)setUpSwip{ // 默認只能從左往右 UISwipeGestureRecognizer *swip = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swip)]; // 設置其方向可以左右清掃 swip.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight; [self.image addGestureRecognizer:swip]; // 默認只能從左往右 UISwipeGestureRecognizer *swip2 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swip)]; // 設置其方向可以上下清掃 swip2.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp; [self.image addGestureRecognizer:swip2];}- (void)swip{ NSLog(@"%s", __func__);}
#pragma mark - 旋轉- (void)setUpRotation{ UIRotationGestureRecognizer *ratation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)]; ratation.delegate = self; [self.image addGestureRecognizer:ratation];}- (void)rotation:(UIRotationGestureRecognizer *)rotacion{ self.image.transform = CGAffineTransformRotate(self.image.transform, rotacion.rotation); // 復位 rotacion.rotation = 0;}
#pragma mark - 長按手勢識別器- (void)setUpLong{ // 長按手勢默認會掉兩次@selecter中的方法 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; [self.image addGestureRecognizer:longPress];}// 默認會觸發兩次- (void)longPress:(UILongPressGestureRecognizer *)longPress{ if (longPress.state == UIGestureRecognizerStateEnded) { NSLog(@"%s", __func__); }}
新聞熱點
疑難解答