天天看點

觸摸事件UITouch的用法

觸摸螢幕是iOS裝置接受使用者輸入的主要方式,包括單擊、輕按兩下、撥動以及多點觸摸等,這些操作都會産生觸摸事件。

在Cocoa中,代表觸摸對象的類是UITouch。當使用者觸摸螢幕後,就會産生相應的事件,所有相關的UITouch對象都被包裝在事件中,被程式交由特定的對象來處理。UITouch對象直接包括觸摸的詳細資訊。

UITouch類中包含5個屬性:

 window:    觸摸産生時所處的視窗。由于視窗可能發生變化,目前所在的視窗不一定是最開始的視窗。

 view:              觸摸産生時所處的視圖。由于視圖可能發生變化,目前視圖也不一定時最初的視圖。

 tapCount:輕擊(Tap)操作和滑鼠的單擊操作類似,tapCount表示短時間内輕擊螢幕的次數。是以可以根據tapCount判斷單擊、輕按兩下或更多的輕擊。

 timestamp:  時間戳記錄了觸摸事件産生或變化時的時間。機關是秒。

 phase:        觸摸事件在螢幕上有一個周期,即觸摸開始、觸摸點移動、觸摸結束,還有中途取消。通過phase可以檢視目前觸摸事件在一個周期中所處的狀态。

phase是UITouchPhase類型的,這是一個枚舉配型,包含了:

UITouchPhaseBegan(觸摸開始)

UITouchPhaseMoved(接觸點移動) 

UITouchPhaseStationary(接觸點無移動)

UITouchPhaseEnded(觸摸結束)

 UITouchPhaseCancelled(觸摸取消)

UITouch類中包含如下成員函數:

- (CGPoint)locationInView:(UIView *)view:函數傳回一個CGPoint類型的值,表示觸摸在view這個視圖上的位置,這裡傳回的位置是針對view的坐标系的。調用時傳入的view參數為空的話,傳回的時觸摸點在整個視窗的位置。

- (CGPoint)previousLocationInView:(UIView *)view:該方法記錄了前一個坐标值,函數傳回也是一個CGPoint類型的值, 表示觸摸在view這個視圖上的位置,這裡傳回的位置是針對view的坐标系的。調用時傳入的view參數為空的話,傳回的時觸摸點在整個視窗的位置。

        當手指接觸到螢幕,不管是單點觸摸還是多點觸摸,事件都會開始,直到使用者所有的手指都離開螢幕。期間所有的UITouch對象都被包含在UIEvent事件對象中,由程式分發給處理者。事件記錄了這個周期中所有觸摸對象狀态的變化。

        隻要螢幕被觸摸,系統就會報若幹個觸摸的資訊封裝到UIEvent對象中發送給程式,由管理程式UIApplication對象将事件分發。一般來說,事件将被發給主視窗,然後傳給第一響應者對象(FirstResponder)處理。

關于響應者的概念,通過以下幾點說明:

響應者對象(Response object)

響應者對象就是可以響應事件并對事件作出處理。在iOS中,存在UIResponder類,它定義了響應者對象的所有方法。UIApplication、UIView等類都繼承了UIResponder類,UIWindow和UIKit中的控件因為繼承了UIView,是以也間接繼承了UIResponder類,這些類的執行個體都可以當作響應者。

    第一響應者(First responder):

       目前接受觸摸的響應者對象被稱為第一響應者,即表示目前該對象正在與使用者互動,它是響應者鍊的開端。

 響應者鍊(Responder chain):

      響應者連結清單示一系列的響應者對象。事件被交由第一響應者對象處理,如果第一響應者不處理,事件被沿着響應者鍊向上傳遞,交給下一個響應者(next responder)。一般來說,第一響應者是個視圖對象或者其子類對象,當其被觸摸後事件被交由它處理,如果它不處理,事件就會被傳遞給它的視圖控制器對象(如果存在),然後是它的父視圖(superview)對象(如果存在),以此類推,直到頂層視圖。接下來會沿着頂層視圖(top view)到視窗(UIWindow對象)再到程式(UIApplication對象)。如果整個過程都沒有響應這個事件,該事件就被丢棄。一般情況下,在響應者鍊中隻要由對象處理事件,事件就停止傳遞。但有時候可以在視圖的響應方法中根據一些條件判斷來決定是否需要繼續傳遞事件。

管理事件分發

視圖對觸摸事件是否需要作處回應可以通過設定視圖的userInteractionEnabled屬性。預設狀态為YES,如果設定為NO,可以阻止視圖接收和分發觸摸事件。除此之外,當視圖被隐藏(setHidden:YES)或者透明(alpha值為0)也不會收事件。不過這個屬性隻對視圖有效,如果想要整個程式都步響應事件,可以調用UIApplication的beginIngnoringInteractionEvents方法來完全停止事件接收和分發。通過endIngnoringInteractionEvents方法來恢複讓程式接收和分發事件。如果要讓視圖接收多點觸摸,需要設定它的multipleTouchEnabled屬性為YES,預設狀态下這個屬性值為NO,即視圖預設不接收多點觸摸。

處理使用者的觸摸事件

首先觸摸的對象是視圖,而視圖的類UIView繼承了UIRespnder類,但是要對事件作出處理,還需要重寫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;

            當手指接觸螢幕時,就會調用touchesBegan:withEvent方法;

            當手指在螢幕上移時,動就會調用touchesMoved:withEvent方法;

            當手指離開螢幕時,就會調用touchesEnded:withEvent方法;

            當觸摸被取消(比如觸摸過程中被來電打斷),就會調用touchesCancelled:withEvent方法。而這幾個方法被調用時,正好對應了UITouch類中phase屬性的4個枚舉值。

            上面的四個事件方法,在開發過程中并不要求全部實作,可以根據需要重寫特定的方法。對于這4個方法,都有兩個相同的參數:NSSet類型的touches和UIEvent類型的event。其中touches表示觸摸産生的所有UITouch對象,而event表示特定的事件。因為UIEvent包含了整個觸摸過程中所有的觸摸對象,是以可以調用allTouches方法擷取該事件内所有的觸摸對象,也可以調用touchesForVIew:或者touchesForWindows:取出特定視圖或者視窗上的觸摸對象。在這幾個事件中,都可以拿到觸摸對象,然後根據其位置,狀态,時間屬性做邏輯處理。

下面是移動某一個試圖内的子視圖的小動畫的實作效果,代碼不全,精髓在其中:

[html]  view plain copy

  1. -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  2. {  
  3.     UITouch *touch = [touches anyObject];  
  4.     if([self.view pointInside:[touch locationInView:rollView] withEvent:nil])  
  5.         originLocation = [touch locationInView:self.view];  
  6. }  
  7. -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event  
  8. {  
  9.     UITouch *touch = [touches anyObject];  
  10.     if([self.view pointInside:[touch locationInView:rollView] withEvent:nil])  
  11.     {  
  12.         CGPoint currentLocation = [touch locationInView:self.view];  
  13.         CGRect frame = rollLabel.frame;  
  14.         frame.origin.x = currentLocation.x - originLocation.x;  
  15.         if(frame.origin.x < -10)  
  16.             frame.origin.x = -10;  
  17.         if(frame.origin.x > rollView.frame.size.width)  
  18.             frame.origin.x = rollView.frame.size.width;  
  19.         frame.origin.y = labelLocation.y;  
  20.         rollLabel.frame = frame;  
  21.     }  
  22. }  

可以根據自己的需求對上面的代碼進行修改。

下面是在ios開發中常見的功能。即touch移動事件,是移動到目前視圖的子視圖中,還是移動到目前視圖以外了。

辦法是,繼承UIView,覆寫touchesMoved方法:

[html]  view plain copy

  1. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{   
  2.     UITouch *touch=[touches anyObject];   
  3.     if (![self pointInside:[touch locationInView:self] withEvent:nil]) {   
  4.         NSLog(@"touches moved outside the view");   
  5.     }else {   
  6.         UIView *hitView=[self hitTest:[[touches anyObject] locationInView:self] withEvent:nil];   
  7.         if (hitView==self) {   
  8.             NSLog(@"touches moved in the view");   
  9.         }else{   
  10.             NSLog(@"touches moved in the subview");   
  11.         }   
  12.     }   
  13. }  

本文轉載位址 http://blog.csdn.net/enuola/article/details/8291402