• iOS中的事件可以分為3大類型
- 觸摸事件
- 加速計事件
- 遠程控制事件
響應者對象
• 在iOS中不是任何對象都能處理事件,只有繼承了UIResponder的對象才能接收並處理事 件。我們稱之為“響應者對象”
• UIApplication、UIViewController、UIView都繼承自UIResponder,因此它們 都是響應者對象,都能夠接收並處理事件
UIResponder
• 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;
UIView的觸摸事件處理
• UIView是UIResponder的子類,可以覆蓋下列4個方法處理不同的觸摸事件
➢ 一根或者多根手指開始觸摸view,系統會自動調用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
➢ 一根或者多根手指在view上移動,系統會自動調用view的下面方法(隨着手指的移動, 會持續調用該方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event ➢ 一根或者多根手指離開view,系統會自動調用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
➢ 觸摸結束前,某個系統事件(例如電話呼入)會打斷觸摸過程,系統會自動調用view的下面
方法
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
提示:touches中存放的都是UITouch對象
UITouch
• 當用戶用一根觸摸屏幕時,會創建一個與手指相關聯的UITouch對象 • 一根手指對應一個UITouch對象
• UITouch的作用
➢ 保存着跟手指相關的信息,比如觸摸的位置、時間、階段
• 當手指移動時,系統會更新同一個UITouch對象,使之能夠一直保存該手指在的觸摸位置 • 當手指離開屏幕時,系統會銷毀相應的UITouch對象
• 提示:iPhone開發中,要避免使用雙擊事件!
UITouch的屬性
• 觸摸產生時所處的視圖
@property(nonatomic,readonly,retain) UIView *view;
• 短時間內點按屏幕的次數,可以根據tapCount判斷單擊、雙擊或更多的點擊
@property(nonatomic,readonly) NSUInteger tapCount;
• 記錄了觸摸事件產生或變化時的時間,單位是秒
@property(nonatomic,readonly) NSTimeInterval timestamp;
• 當前觸摸事件所處的狀態
@property(nonatomic,readonly) UITouchPhase phase;
UITouch的方法
- 返回值表示觸摸在view上的位置
- 這里返回的位置是針對view的坐標系的(以view的左上角為原點(0, 0))
- 調用時傳入的view參數為nil的話,返回的是觸摸點在UIWindow的位置
- (CGPoint)previousLocationInView:(UIView *)view;
- 該方法記錄了前一個觸摸點的位置
UIEvent
• 每產生一個事件,就會產生一個UIEvent對象
• UIEvent:稱為事件對象,記錄事件產生的時刻和類型
• 常見屬性
➢ 事件類型
@property(nonatomic,readonly) UIEventType type; @property(nonatomic,readonly) UIEventSubtype subtype;
➢ 事件產生的時間
@property(nonatomic,readonly) NSTimeInterval timestamp;
• UIEvent還提供了相應的方法可以獲得在某個view上面的觸摸對象(UITouch)
touches和event參數
➢觸摸開始:- (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兩個參數
➢ 如果兩根手指同時觸摸一個view,那么view只會調用一次touchesBegan:withEvent:
➢ 一次完整的觸摸過程中,只會產生一個事件對象,4個觸摸方法都是同一個event參數
方法,touches參數中裝着2個UITouch對象
➢ 如果這兩根手指一前一后分開觸摸同一個view,那么view會分別調用2 次touchesBegan:withEvent:方法,並且每次調用 時 的touches參數中只包含一 個UITouch對象
➢ 根據touches中UITouch的個數可以判斷出是單點觸摸還是多點觸摸
事件的產生和傳遞
• 發生觸摸事件后,系統會將該事件加入到一個由UIApplication管理的事件隊列中
• UIApplication會從事件隊列中取出最前面的事件,並將事件分發下去以便處理,通
常,先發送事件給應用程序的主窗又(keyWindow)
• 主窗又會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件,這也是整個事件處理
過程的第一步
• 找到合適的視圖控件后,就會調用視圖控件的touches方法來作具體的事件處理
➢ touchesBegan...
➢ touchesMoved...
➢ touchedEnded...
事件傳遞示例
- 觸摸事件的傳遞是從父控件傳遞到子控件
- 如果父控件不能接收觸摸事件,那么子控件就不可能接收到觸摸事件(掌握)
- 如何找到最合適的控件來處理事件?
- 自己是否能接收觸摸事件?
- 觸摸點是否在自己身上?
- 從后往前遍歷子控件,重復前面的兩個步驟
- 如果沒有符合條件的子控件,那么就自己最適合處理
UIView不接收觸摸事件的三種情況
- 不接收用戶交互 userInteractionEnabled = NO
- 隱藏 hidden = YES
- 透明 alpha = 0.0 ~ 0.01
提示:UIImageView的userInteractionEnabled默認就是NO,因此UIImageView以 及它的子控件默認是不能接收觸摸事件的

// 觸摸事件完整的調用過程touchesBegan --> touchesMoved --> touchesEnded // 當手指觸摸view的時候調用 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // [event allTouches] == touches // NSArray:用來保存同一種類型的有序的值 // NSSet: 用來保存無序的值 // NSArray *arr = @[@"1", @"2", @"3"]; // arr[2]; // NSSet set = @[@"2", @"3",@"1"]; // UITouch *touch = [touches anyObject]; // 獲取手指觸摸的位置 // 如果locationInView傳遞self, 將來獲取出來的位置,是以自己的左上角為原點(00) // 如果傳遞的是父視圖,將來獲取出來的位置,是以父視圖的左上角為原點(00) // CGPoint point = [touch locationInView:self.superview]; // NSLog(@"touchesBegan %@", NSStringFromCGPoint(point)); // 獲取手指點擊的次數 // NSLog(@"tapCount = %d", touch.tapCount); // NSLog(@"touchesBegan %p", touch); NSLog(@"%d", touches.count); } // 當手指在view上移動的時候調用 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // UITouch *touch = [touches anyObject]; // NSLog(@"touchesMoved %p", touch); UITouch *touch = [touches anyObject]; // 0. 獲取上一次的位置 CGPoint prePoint = [touch previousLocationInView:self]; // NSLog(@"prePoint = %@", NSStringFromCGPoint(prePoint)); // 1.獲取當前的位置 CGPoint currentPoint = [touch locationInView:self]; // NSLog(@"currentPoint = %@", NSStringFromCGPoint(currentPoint)); CGFloat moveX = currentPoint.x - prePoint.x; CGFloat moveY = currentPoint.y - prePoint.y; // NSLog(@"moveX = %.1f", moveX); // 2.改變當前視圖的位置,為手指指定的位置 CGPoint temp = self.center; // NSLog(@"%f,%f",self.bounds.origin.x,self.bounds.origin.y); temp.x += moveX; temp.y += moveY; self.center = temp; } // 當手指離開view的時候調用 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // UITouch *touch = [touches anyObject]; // NSLog(@"touchesEnded %p", touch); } // 當觸摸事件被打斷的時候調用 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { }