日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

移动开发:iphone开发之触摸事件详解

發(fā)布時(shí)間:2023/12/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 移动开发:iphone开发之触摸事件详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn):http://blog.sina.com.cn/s/blog_8988732e01012eaf.html

iPhoneOS中的觸摸事件基于多點(diǎn)觸摸模型。用戶不是通過鼠標(biāo)和鍵盤,而是通過觸摸設(shè)備的屏幕來操作對(duì)象、輸入數(shù)據(jù)、以及指示自己的意圖。iPhoneOS將一個(gè)或多個(gè)和屏幕接觸的手指識(shí)別為多點(diǎn)觸摸序列的一部分,該序列從第一個(gè)手指碰到屏幕開始,直到最后一個(gè)手指離開屏幕結(jié)束。iPhoneOS通過一個(gè)多點(diǎn)觸摸序列來跟蹤與屏幕接觸的手指,記錄每個(gè)手指的觸摸特征,包括手指在屏幕上的位置和發(fā)生觸摸的時(shí)間。應(yīng)用程序通常將特定組合的觸摸識(shí)別為手勢,并以用戶直覺的方式來進(jìn)行響應(yīng),比如對(duì)收縮雙指距離的手勢,程序的響應(yīng)是縮小顯示的內(nèi)容;對(duì)輕拂屏幕的手勢,則響應(yīng)為滾動(dòng)顯示內(nèi)容。

請(qǐng)注意:手指在屏幕上能達(dá)到的精度和鼠標(biāo)指針有很大的不同。當(dāng)用戶觸擊屏幕時(shí),接觸區(qū)域?qū)嶋H上是橢圓形的,而且比用戶想像的位置更靠下一點(diǎn)。根據(jù)觸摸屏幕的手指、手指的尺寸、手指接觸屏幕的力量、手指的方向、以及其它因素的不同,其“接觸部位”的尺寸和形狀也有所不同。底層的多點(diǎn)觸摸系統(tǒng)會(huì)分析所有的這些信息,為您計(jì)算出單一的觸點(diǎn)。

很多UIKit類對(duì)多點(diǎn)觸摸事件的處理方式不同于它的對(duì)象實(shí)例,特別是像UIButton和UISlider這樣的UIControl的子類。這些子類的對(duì)象—被稱為控件對(duì)象—只接收特定類型的手勢,比如觸擊或向特定方向拖拽??丶?duì)象在正確配置之后,會(huì)在某種手勢發(fā)生后將動(dòng)作消息發(fā)送給目標(biāo)對(duì)象。其它的UIKit類則在其它的上下文中處理手勢,比如UIScrollView可以為表格視圖和具有很大內(nèi)容區(qū)域的文本視圖提供滾動(dòng)行為。

某些應(yīng)用程序可能不需要直接處理事件,它們可以依賴UIKit類實(shí)現(xiàn)的行為。但是,如果您創(chuàng)建了UIView的定制子類—這是iPhoneOS系統(tǒng)開發(fā)的常見模式—且希望該視圖響應(yīng)特定的觸摸事件,就需要實(shí)現(xiàn)處理該事件所需要的代碼。而且,如果您希望一個(gè)UIKit對(duì)象以不同的方式響應(yīng)事件,就必須創(chuàng)建框架類的子類,并重載相應(yīng)的事件處理方法。

事件和觸摸

在iPhone OS中,觸摸動(dòng)作是指手指碰到屏幕或在屏幕上移動(dòng),它是一個(gè)多點(diǎn)觸摸序列的一部分。比如,一個(gè)pinch-close手勢就包含兩個(gè)觸摸動(dòng)作:即屏幕上的兩個(gè)手指從相反方向靠近對(duì)方。一些單指手勢則比較簡單,比如觸擊、雙擊、或輕拂(即用戶快速碰擦屏幕)。應(yīng)用程序也可以識(shí)別更為復(fù)雜的手勢,舉例來說,如果一個(gè)應(yīng)用程序使用具有轉(zhuǎn)盤形狀的定制控件,用戶就需要用多個(gè)手指來“轉(zhuǎn)動(dòng)”轉(zhuǎn)盤,以便進(jìn)行某種精調(diào)。

事件是當(dāng)用戶手指觸擊屏幕及在屏幕上移動(dòng)時(shí),系統(tǒng)不斷發(fā)送給應(yīng)用程序的對(duì)象。事件對(duì)象為一個(gè)多點(diǎn)觸摸序列中所有觸摸動(dòng)作提供一個(gè)快照,其中最重要的是特定視圖中新發(fā)生或有變化的觸摸動(dòng)作。一個(gè)多點(diǎn)觸摸序列從第一個(gè)手指碰到屏幕開始,其它手指隨后也可能觸碰屏幕,所有手指都可能在屏幕上移動(dòng)。當(dāng)最后一個(gè)手指離開屏幕時(shí),序列就結(jié)束了。在觸摸的每個(gè)階段,應(yīng)用程序都會(huì)收到事件對(duì)象。

觸摸信息有時(shí)間和空間兩方面,時(shí)間方面的信息稱為階段(phrase),表示觸摸是否剛剛開始、是否正在移動(dòng)或處于靜止?fàn)顟B(tài),以及何時(shí)結(jié)束—也就是手指何時(shí)從屏幕舉起(參見圖3-1)。觸摸信息還包括當(dāng)前在視圖或窗口中的位置信息,以及之前的位置信息(如果有的話)。當(dāng)一個(gè)手指接觸屏幕時(shí),觸摸就和某個(gè)窗口或視圖關(guān)聯(lián)在一起,這個(gè)關(guān)聯(lián)在事件的整個(gè)生命周期都會(huì)得到維護(hù)。如果有多個(gè)觸摸同時(shí)發(fā)生,則只有和同一個(gè)視圖相關(guān)聯(lián)的觸摸會(huì)被一起處理。類似地,如果兩個(gè)觸摸事件發(fā)生的間隔時(shí)間很短,也只有當(dāng)它們和同一個(gè)視圖相關(guān)聯(lián)時(shí),才會(huì)被處理為多觸擊事件。

圖3-1?多點(diǎn)觸摸序列和觸摸階段

在iPhone OS中,一個(gè)UITouch對(duì)象表示一個(gè)觸摸,一個(gè)UIEvent對(duì)象表示一個(gè)事件。事件對(duì)象中包含與當(dāng)前多點(diǎn)觸摸序列相對(duì)應(yīng)的所有觸摸對(duì)象,還可以提供與特定視圖或窗口相關(guān)聯(lián)的觸摸對(duì)象(參見圖3-2)。在一個(gè)觸摸序列發(fā)生的過程中,對(duì)應(yīng)于特定手指的觸摸對(duì)象是持久的,在跟蹤手指運(yùn)動(dòng)的過程中,UIKit會(huì)對(duì)其進(jìn)行修改。發(fā)生改變的觸摸屬性變量有觸摸階段、觸摸在視圖中的位置、發(fā)生變化之前的位置、以及時(shí)間戳。事件處理代碼通過檢查這些屬性的值來確定如何響應(yīng)事件。

圖3-2?UIEvent對(duì)象及其UITouch對(duì)象間的關(guān)系

系統(tǒng)可能隨時(shí)取消多點(diǎn)觸摸序列,進(jìn)行事件處理的應(yīng)用程序必須做好正確響應(yīng)的準(zhǔn)備。事件的取消可能是由于重載系統(tǒng)事件引起的,電話呼入就是這樣的例子。

事件的傳遞

系統(tǒng)將事件按照特定的路徑傳遞給可以對(duì)其進(jìn)行處理的對(duì)象。如“核心應(yīng)用程序架構(gòu)”部分描述的那樣,當(dāng)用戶觸摸設(shè)備屏幕時(shí),iPhoneOS會(huì)將它識(shí)別為一組觸摸對(duì)象,并將它們封裝在一個(gè)UIEvent對(duì)象中,放入當(dāng)前應(yīng)用程序的事件隊(duì)列中。事件對(duì)象將特定時(shí)刻的多點(diǎn)觸摸序列封裝為一些觸摸對(duì)象。負(fù)責(zé)管理應(yīng)用程序的UIApplication單件對(duì)象將事件從隊(duì)列的頂部取出,然后派發(fā)給其它對(duì)象進(jìn)行處理。典型情況下,它會(huì)將事件發(fā)送給應(yīng)用程序的鍵盤焦點(diǎn)窗口—即擁有當(dāng)前用戶事件焦點(diǎn)的窗口,然后代表該窗口的UIWindow對(duì)象再將它發(fā)送給第一響應(yīng)者進(jìn)行處理(第一響應(yīng)者在?“響應(yīng)者對(duì)象和響應(yīng)者鏈”部分中描述)

應(yīng)用程序通過觸碰測試(hit-testing)來尋找事件的第一響應(yīng)者,即通過遞歸調(diào)用視圖層次中視圖對(duì)象的hitTest:withEvent:方法來確認(rèn)發(fā)生觸摸的子視圖。觸摸對(duì)象的整個(gè)生命周期都和該視圖互相關(guān)聯(lián),即使觸摸動(dòng)作最終移動(dòng)到該視圖區(qū)域之外也是如此。“事件處理技巧”部分對(duì)觸碰測試在編程方面的一些隱含意義進(jìn)行討論。

UIApplication對(duì)象和每個(gè)UIWindow對(duì)象都在sendEvent:方法(兩個(gè)類都聲明了這個(gè)方法)中派發(fā)事件。由于這些方法是事件進(jìn)入應(yīng)用程序的通道,所以,您可以從UIApplication或UIWindow派生出子類,重載其sendEvent:方法,實(shí)現(xiàn)對(duì)事件的監(jiān)控或執(zhí)行特殊的事件處理。但是,大多數(shù)應(yīng)用程序都不需要這樣做。

響應(yīng)者對(duì)象和響應(yīng)者鏈

響應(yīng)者對(duì)象是可以響應(yīng)事件并對(duì)其進(jìn)行處理的對(duì)象。UIResponder是所有響應(yīng)者對(duì)象的基類,它不僅為事件處理,而且也為常見的響應(yīng)者行為定義編程接口。UIApplication、UIView、和所有從UIView派生出來的UIKit類(包括UIWindow)都直接或間接地繼承自UIResponder類。

第一響應(yīng)者是應(yīng)用程序中當(dāng)前負(fù)責(zé)接收觸摸事件的響應(yīng)者對(duì)象(通常是一個(gè)UIView對(duì)象)。UIWindow對(duì)象以消息的形式將事件發(fā)送給第一響應(yīng)者,使其有機(jī)會(huì)首先處理事件。如果第一響應(yīng)者沒有進(jìn)行處理,系統(tǒng)就將事件(通過消息)傳遞給響應(yīng)者鏈中的下一個(gè)響應(yīng)者,看看它是否可以進(jìn)行處理。

響應(yīng)者鏈是一系列鏈接在一起的響應(yīng)者對(duì)象,它允許響應(yīng)者對(duì)象將處理事件的責(zé)任傳遞給其它更高級(jí)別的對(duì)象。隨著應(yīng)用程序?qū)ふ夷軌蛱幚硎录膶?duì)象,事件就在響應(yīng)者鏈中向上傳遞。響應(yīng)者鏈由一系列“下一個(gè)響應(yīng)者”組成,其順序如下:

  • 第一響應(yīng)者將事件傳遞給它的視圖控制器(如果有的話),然后是它的父視圖。

  • 類似地,視圖層次中的每個(gè)后續(xù)視圖都首先傳遞給它的視圖控制器(如果有的話),然后是它的父視圖。

  • 最上層的容器視圖將事件傳遞給UIWindow對(duì)象。
  • UIWindow對(duì)象將事件傳遞給UIApplication單件對(duì)象。

  • 如果應(yīng)用程序找不到能夠處理事件的響應(yīng)者對(duì)象,則丟棄該事件。

    響應(yīng)者鏈中的所有響應(yīng)者對(duì)象都可以實(shí)現(xiàn)UIResponder的某個(gè)事件處理方法,因此也都可以接收事件消息。但是,它們可能不愿處理或只是部分處理某些事件。如果是那樣的話,它們可以將事件消息轉(zhuǎn)送給下一個(gè)響應(yīng)者,方法大致如下:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch* touch = [touches anyObject];
    NSUInteger numTaps = [touch tapCount];
    if (numTaps < 2) {
    [self.nextResponder touchesBegan:touches withEvent:event];
    } else {
    [self handleDoubleTap:touch];
    }
    }

    請(qǐng)注意:如果一個(gè)響應(yīng)者對(duì)象將一個(gè)多點(diǎn)觸摸序列的初始階段的事件處理消息轉(zhuǎn)發(fā)給下一個(gè)響應(yīng)者(在touchesBegan:withEvent:方法中),就應(yīng)該同樣轉(zhuǎn)發(fā)該序列的其它事件處理消息。

    動(dòng)作消息的處理也使用響應(yīng)者鏈。當(dāng)用戶對(duì)諸如按鍵或分頁控件這樣的UIControl對(duì)象進(jìn)行操作時(shí),控件對(duì)象(如果正確配置的話)會(huì)向目標(biāo)對(duì)象發(fā)送動(dòng)作消息。但是,如果目標(biāo)對(duì)象被指定為nil,應(yīng)用程序就會(huì)像處理事件消息那樣,把該動(dòng)作消息路由給第一響應(yīng)者。如果第一響應(yīng)者沒有進(jìn)行處理,再發(fā)送給其下一個(gè)響應(yīng)者,以此類推,將消息沿著響應(yīng)者鏈向上傳遞。

    調(diào)整事件的傳遞

    UIKit為應(yīng)用程序提供了一些簡化事件處理、甚至完全關(guān)閉事件流的編程接口。下面對(duì)這些方法進(jìn)行總結(jié):

    • 關(guān)閉事件的傳遞。缺省情況下,視圖會(huì)接收觸摸事件。但是,您可以將其userInteractionEnabled屬性聲明設(shè)置為NO,關(guān)閉事件傳遞的功能。隱藏或透明的視圖也不能接收事件。

    • 在一定的時(shí)間內(nèi)關(guān)閉事件的傳遞。應(yīng)用程序可以調(diào)用UIApplication的beginIgnoringInteractionEvents方法,并在隨后調(diào)用endIgnoringInteractionEvents方法來實(shí)現(xiàn)這個(gè)目的。前一個(gè)方法使應(yīng)用程序完全停止接收觸摸事件消息,第二個(gè)方法則重啟消息的接收。某些時(shí)候,當(dāng)您的代碼正在執(zhí)行動(dòng)畫時(shí),可能希望關(guān)閉事件的傳遞。

    • 打開多點(diǎn)觸摸的傳遞。?缺省情況下,視圖只接收多點(diǎn)觸摸序列的第一個(gè)觸摸事件,而忽略所有其它事件。如果您希望視圖處理多點(diǎn)觸摸,就必須使它啟用這個(gè)功能。在代碼或InterfaceBuilder的查看器窗口中將視圖的multipleTouchEnabled屬性設(shè)置為YES,就可以實(shí)現(xiàn)這個(gè)目標(biāo)。

    • 將事件傳遞限制在某個(gè)單獨(dú)的視圖上。?缺省情況下,視圖的exclusiveTouch屬性被設(shè)置為NO。將這個(gè)屬性設(shè)置為YES會(huì)使相應(yīng)的視圖具有這樣的特性:即當(dāng)該視圖正在跟蹤觸摸動(dòng)作時(shí),窗口中的其它視圖無法同時(shí)進(jìn)行跟蹤,它們不能接收到那些觸摸事件。然而,一個(gè)標(biāo)識(shí)為“獨(dú)占觸摸”的視圖不能接收與同一窗口中其它視圖相關(guān)聯(lián)的觸摸事件。如果一個(gè)手指接觸到一個(gè)獨(dú)占觸摸的視圖,則僅當(dāng)該視圖是窗口中唯一一個(gè)跟蹤手指的視圖時(shí),觸摸事件才會(huì)被傳遞。如果一個(gè)手指接觸到一個(gè)非獨(dú)占觸摸的視圖,則僅當(dāng)窗口中沒有其它獨(dú)占觸摸視圖跟蹤手指時(shí),該觸摸事件才會(huì)被傳遞。

    • 將事件傳遞限制在子視圖上。一個(gè)定制的UIView類可以通過重載hitTest:withEvent:方法來將多點(diǎn)觸摸事件的傳遞限制在它的子視圖上。這個(gè)技巧的討論請(qǐng)參見“事件處理技巧”部分。

    處理多點(diǎn)觸摸事件

    為了處理多點(diǎn)觸摸事件,UIView的定制子類(比較不常見的還有UIApplication或UIWindow的定制子類)必須至少實(shí)現(xiàn)一個(gè)UIResponder的事件處理方法。本文的下面部分將對(duì)這些方法進(jìn)行描述,討論處理常見手勢的方法,并展示一個(gè)處理復(fù)雜多點(diǎn)觸摸事件的響應(yīng)者對(duì)象實(shí)例,以及就事件處理的某些技術(shù)提出建議。

    事件處理方法

    在一個(gè)多點(diǎn)觸摸序列發(fā)生的過程中,應(yīng)用程序會(huì)發(fā)出一系列事件消息。為了接收和處理這些消息,響應(yīng)者對(duì)象的類必須至少實(shí)現(xiàn)下面這些由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

    在給定的觸摸階段中,如果發(fā)生新的觸摸動(dòng)作或已有的觸摸動(dòng)作發(fā)生變化,應(yīng)用程序就會(huì)發(fā)送這些消息:

    • 當(dāng)一個(gè)或多個(gè)手指觸碰屏幕時(shí),發(fā)送touchesBegan:withEvent:消息。

    • 當(dāng)一個(gè)或多個(gè)手指在屏幕上移動(dòng)時(shí),發(fā)送touchesMoved:withEvent:消息。

    • 當(dāng)一個(gè)或多個(gè)手指離開屏幕時(shí),發(fā)送touchesEnded:withEvent:消息。

    • 當(dāng)觸摸序列被諸如電話呼入這樣的系統(tǒng)事件所取消時(shí),發(fā)送touchesCancelled:withEvent:消息。

    上面這些方法都和特定的觸摸階段(比如UITouchPhaseBegan)相關(guān)聯(lián),該信息存在于UITouch對(duì)象的phase屬性聲明中。

    每個(gè)與事件處理方法相關(guān)聯(lián)的消息都有兩個(gè)參數(shù)。第一個(gè)參數(shù)是一個(gè)UITouch對(duì)象的集合,表示給定階段中新的或者發(fā)生變化的觸摸動(dòng)作;第二個(gè)參數(shù)是一個(gè)UIEvent對(duì)象,表示這個(gè)特定的事件。您可以通過這個(gè)事件對(duì)象得到與之相關(guān)聯(lián)的所有觸摸對(duì)象(allTouches),或者發(fā)生在特定的視圖或窗口上的觸摸對(duì)象子集。其中的某些觸摸對(duì)象表示自上次事件消息以來沒有發(fā)生變化,或雖然發(fā)生變化但處于不同階段的觸摸動(dòng)作。

    為了處理給定階段的事件,響應(yīng)者對(duì)象常常從傳入的集合參數(shù)中取得一或多個(gè)UITouch對(duì)象,然后考察這些對(duì)象的屬性或取得它們的位置(如果需要處理所有觸摸對(duì)象,可以向該NSSet對(duì)象發(fā)送anyObject消息)。UITouch類中有一個(gè)名為locationInView:的重要方法,如果傳入self參數(shù)值,它會(huì)給出觸摸動(dòng)作在響應(yīng)者坐標(biāo)系統(tǒng)中的位置(假定該響應(yīng)者是一個(gè)UIView對(duì)象,且傳入的視圖參數(shù)不為nil)。另外,還有一個(gè)與之平行的方法,可以給出觸摸動(dòng)作之前位置(previousLocationInView:)。UITouch實(shí)例的屬性還可以給出發(fā)生多少次觸碰(tapCount)、觸摸對(duì)象的創(chuàng)建或最后一次變化發(fā)生在什么時(shí)間(timestamp)、以及觸摸處于什么階段(phase)。

    響應(yīng)者類并不是必須實(shí)現(xiàn)上面列出的所有三個(gè)事件方法。舉例來說,如果它只對(duì)手指離開屏幕感興趣,則只需要實(shí)現(xiàn)touchesEnded:withEvent:方法就可以了。

    在一個(gè)多點(diǎn)觸摸序列中,如果響應(yīng)者在處理事件時(shí)創(chuàng)建了某些持久對(duì)象,則應(yīng)該實(shí)現(xiàn)touchesCancelled:withEvent:方法,以便當(dāng)系統(tǒng)取消該序列的時(shí)候?qū)ζ溥M(jìn)行清理。多點(diǎn)觸摸序列的取消常常發(fā)生在應(yīng)用程序的事件處理遭到外部事件—比如電話呼入—破壞的時(shí)候。請(qǐng)注意,響應(yīng)者對(duì)象同樣應(yīng)該在收到多點(diǎn)觸摸序列的touchesEnded:withEvent:消息時(shí)清理之前創(chuàng)建的對(duì)象(“事件處理技巧”部分討論了如何確定一個(gè)序列中的最后一個(gè)touch-up事件)。

    處理單個(gè)和多個(gè)觸碰手勢

    iPhone應(yīng)用程序中一個(gè)很常見的手勢是觸擊:即用戶用手指觸碰一個(gè)對(duì)象。響應(yīng)者對(duì)象可以以一種方式響應(yīng)單擊,而以另外一種方式響應(yīng)雙擊,甚至可能以第三種方式響應(yīng)三次觸擊。您可以通過考察UITouch對(duì)象的tapCount屬性聲明值來確定用戶在一個(gè)響應(yīng)者對(duì)象上的觸擊次數(shù),

    取得這個(gè)值的最好地方是touchesBegan:withEvent:和touchesEnded:withEvent:方法。在很多情況下,我們更傾向于后者,因?yàn)樗c用戶手指離開屏幕的階段相對(duì)應(yīng)。在觸摸結(jié)束階段(UITouchPhaseEnded)考察觸擊的次數(shù)可以確定手指是真的觸擊,而不是其它動(dòng)作,比如手指接觸屏幕后拖動(dòng)的動(dòng)作。

    程序清單3-1展示了如何檢測某個(gè)視圖上是否發(fā)生雙擊。

    程序清單3-1??檢測雙擊手勢

    - (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
    {
    UITouch *touch = [touches anyObject];
    if ([touch tapCount] == 2) {
    CGPoint tapPoint = [theTouch locationInView:self];
    // Process a double-tap gesture
    }
    }

    當(dāng)一個(gè)響應(yīng)者對(duì)象希望以不同的方式響應(yīng)單擊和雙擊事件時(shí),就會(huì)出現(xiàn)復(fù)雜的情況。舉例來說,單擊的結(jié)果可能是選定一個(gè)對(duì)象,而雙擊則可能是顯示一個(gè)編輯視圖,用于編輯被雙擊的對(duì)象。那么,響應(yīng)者對(duì)象如何知道一個(gè)單擊不是另一個(gè)雙擊的起始部分呢?我們接下來解釋響應(yīng)者對(duì)象如何借助上文剛剛描述的事件處理方法來處理這種情況:

  • 在touchesEnded:withEvent:方法中,當(dāng)觸擊次數(shù)為一時(shí),響應(yīng)者對(duì)象就向自身發(fā)送一個(gè)performSelector:withObject:afterDelay:消息,其中的選擇器標(biāo)識(shí)由響應(yīng)者對(duì)象實(shí)現(xiàn)的、用于處理單擊手勢的方法;第二個(gè)參數(shù)是一個(gè)NSValue或NSDictionary對(duì)象,用于保存相關(guān)的UITouch對(duì)象;時(shí)延參數(shù)則表示單擊和雙擊手勢之間的合理時(shí)間間隔。

    請(qǐng)注意:使用一個(gè)NSValue對(duì)象或字典來保存觸摸對(duì)象是因?yàn)樗鼈儠?huì)保持傳入的對(duì)象。然而,您自己在進(jìn)行事件處理時(shí),不應(yīng)該對(duì)UITouch對(duì)象進(jìn)行保持。

  • 在touchesBegan:withEvent:方法中,如果觸擊次數(shù)為二,響應(yīng)者對(duì)象會(huì)向自身發(fā)送一個(gè)cancelPreviousPerformRequestsWithTarget:消息,取消當(dāng)前被掛起和延期執(zhí)行的調(diào)用。如果觸碰次數(shù)不為二,則在指定的延時(shí)之后,先前步驟中由選擇器標(biāo)識(shí)的方法就會(huì)被調(diào)用,以處理單擊手勢。

  • 在touchesEnded:withEvent:方法中,如果觸碰次數(shù)為二,響應(yīng)者會(huì)執(zhí)行處理雙擊手勢的代碼。

  • 檢測碰擦手勢

    水平和垂直的碰擦(Swipe)是簡單的手勢類型,您可以簡單地在自己的代碼中進(jìn)行跟蹤,并通過它們執(zhí)行某些動(dòng)作。為了檢測碰擦手勢,您需要跟蹤用戶手指在期望的坐標(biāo)軸方向上的運(yùn)動(dòng)。碰擦手勢如何形成是由您自己來決定的,也就是說,您需要確定用戶手指移動(dòng)的距離是否足夠長,移動(dòng)的軌跡是否足夠直,還有移動(dòng)的速度是否足夠快。您可以保存初始的觸碰位置,并將它和后續(xù)的touch-moved事件報(bào)告的位置進(jìn)行比較,進(jìn)而做出這些判斷。

    程序清單3-2展示了一些基本的跟蹤方法,可以用于檢測某個(gè)視圖上發(fā)生的水平碰擦。在這個(gè)例子中,視圖將觸摸的初始位置存儲(chǔ)在名為startTouchPosition的成員變量中。隨著用戶手指的移動(dòng),清單中的代碼將當(dāng)前的觸摸位置和起始位置進(jìn)行比較,確定是否為碰擦手勢。如果觸摸在垂直方向上移動(dòng)得太遠(yuǎn),就會(huì)被認(rèn)為不是碰擦手勢,并以不同的方式進(jìn)行處理。但是,如果手指繼續(xù)在水平方向上移動(dòng),代碼就繼續(xù)將它作為碰擦手勢來處理。一旦碰擦手勢在水平方向移動(dòng)得足夠遠(yuǎn),以至于可以認(rèn)為是完整的手勢時(shí),處理例程就會(huì)觸發(fā)相應(yīng)的動(dòng)作。檢測垂直方向上的碰擦手勢可以用類似的代碼,只是把x和y方向的計(jì)算互換一下就可以了。

    程序清單3-2??在視圖中跟蹤碰擦手勢

    #define HORIZ_SWIPE_DRAG_MIN 12
    #define VERT_SWIPE_DRAG_MAX 4
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    UITouch *touch = [touches anyObject];
    startTouchPosition = [touch locationInView:self];
    }
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self];
    // If the swipe tracks correctly.
    if (fabsf(startTouchPosition.x - currentTouchPosition.x) >= HORIZ_SWIPE_DRAG_MIN &&
    fabsf(startTouchPosition.y - currentTouchPosition.y) <= VERT_SWIPE_DRAG_MAX)
    {
    // It appears to be a swipe.
    if (startTouchPosition.x < currentTouchPosition.x)
    [self myProcessRightSwipe:touches withEvent:event];
    else
    [self myProcessLeftSwipe:touches withEvent:event];
    }
    else
    {
    // Process a non-swipe event.
    }
    }

    處理復(fù)雜的多點(diǎn)觸摸序列

    觸擊和碰擦是簡單的手勢。如何處理更為復(fù)雜的多點(diǎn)觸摸序列—實(shí)際上是解析應(yīng)用程序特有的手勢—取決于應(yīng)用程序希望完成的具體目標(biāo)。您可以跟蹤所有階段的所有觸摸動(dòng)作,記錄觸摸對(duì)象中發(fā)生變化的屬性變量,并正確地改變內(nèi)部的狀態(tài)。

    說明如何處理復(fù)雜的多點(diǎn)觸摸序列的最好方法是通過實(shí)例。程序清單3-3展示一個(gè)定制的UIView對(duì)象如何通過在屏幕上動(dòng)畫移動(dòng)“Welcome”標(biāo)語牌來響應(yīng)用戶手指的移動(dòng),以及如何通過改變歡迎標(biāo)語的語言來響應(yīng)用戶的雙擊手勢(例子中的代碼來自一個(gè)名為MoveMe的示例工程,進(jìn)一步考察該工程可以更好地理解事件處理的上下文)。

    程序清單3-3??處理復(fù)雜的多點(diǎn)觸摸序列

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    UITouch *touch = [[event allTouches] anyObject];
    // Only move the placard view if the touch was in the placard view
    if ([touch view] != placardView) {
    // On double tap outside placard view, update placard's display string
    if ([touch tapCount] == 2) {
    [placardView setupNextDisplayString];
    }
    return;
    }
    // "Pulse" the placard view by scaling up then down
    // Use UIView's built-in animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    CGAffineTransform transform = CGAffineTransformMakeScale(1.2, 1.2);
    placardView.transform = transform;
    [UIView commitAnimations];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    transform = CGAffineTransformMakeScale(1.1, 1.1);
    placardView.transform = transform;
    [UIView commitAnimations];
    // Move the placardView to under the touch
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.25];
    placardView.center = [self convertPoint:[touch locationInView:self] fromView:placardView];
    [UIView commitAnimations];
    }
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
    UITouch *touch = [[event allTouches] anyObject];
    // If the touch was in the placardView, move the placardView to its location
    if ([touch view] == placardView) {
    CGPoint location = [touch locationInView:self];
    location = [self convertPoint:location fromView:placardView];
    placardView.center = location;
    return;
    }
    }
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
    UITouch *touch = [[event allTouches] anyObject];
    // If the touch was in the placardView, bounce it back to the center
    if ([touch view] == placardView) {
    // Disable user interaction so subsequent touches don't interfere with animation
    self.userInteractionEnabled = NO;
    [self animatePlacardViewToCenter];
    return;
    }
    }

    請(qǐng)注意:對(duì)于通過描畫自身的外觀來響應(yīng)事件的定制視圖,在事件處理方法中通常應(yīng)該只是設(shè)置描畫狀態(tài),而在drawRect:方法中執(zhí)行所有的描畫操作。如果需要了解更多關(guān)于描畫視圖內(nèi)容的方法,請(qǐng)參見“圖形和描畫”部分。

    ?

    事件處理技巧

    下面是一些事件處理技巧,您可以在自己的代碼中使用。

    • 跟蹤UITouch對(duì)象的變化

      在事件處理代碼中,您可以將觸摸狀態(tài)的相關(guān)位置保存下來,以便在必要時(shí)和變化之后的UITouch實(shí)例進(jìn)行比較。作為例子,假定您希望將每個(gè)觸摸對(duì)象的最后位置和其初始位置進(jìn)行比較,則在touchesBegan:withEvent:方法中,您可以通過locationInView:方法得到每個(gè)觸摸對(duì)象的初始位置,并以UITouch對(duì)象的地址作為鍵,將它們存儲(chǔ)在CFDictionaryRef封裝類型中;然后,在touchesEnded:withEvent:方法中,可以通過傳入U(xiǎn)ITouch對(duì)象的地址取得該對(duì)象的初始位置,并將它和當(dāng)前位置進(jìn)行比較(您應(yīng)該使用CFDictionaryRef類型,而不是NSDictionary對(duì)象,因?yàn)楹笳咝枰獙?duì)其存儲(chǔ)的項(xiàng)目進(jìn)行拷貝,而UITouch類并不采納NSCopying協(xié)議,該協(xié)議在對(duì)象拷貝過程中是必須的)。

    • 對(duì)子視圖或?qū)由系挠|摸動(dòng)作進(jìn)行觸碰測試

      定制視圖可以用UIView的hitTest:withEvent:方法或CALayer的hitTest:方法來尋找接收觸摸事件的子視圖或?qū)?#xff0c;進(jìn)而正確地處理事件。下面的例子用于檢測定制視圖的層中的“Info”圖像是否被觸碰。

      - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
      CGPoint location = [[touches anyObject] locationInView:self];
      CALayer *hitLayer = [[self layer] hitTest:[self convertPoint:location fromView:nil]];
      if (hitLayer == infoImage) {
      [self displayInfo];
      }
      }

      如果您有一個(gè)攜帶子視圖的定制視圖,就需要明確自己是希望在子視圖的級(jí)別上處理觸摸事件,還是在父視圖的級(jí)別上進(jìn)行處理。如果子視圖沒有實(shí)現(xiàn)touchesBegan:withEvent:、touchesEnded:withEvent:、或者touchesMoved:withEvent:方法,則這些消息就會(huì)沿著響應(yīng)者鏈被傳播到父視圖。然而,由于多次觸碰和多點(diǎn)觸摸事件與發(fā)生這些動(dòng)作所在的子視圖是互相關(guān)聯(lián)的,所以父視圖不會(huì)接收到這些事件。為了保證能接收到所有的觸摸事件,父視圖必須重載hitTest:withEvent:方法,并在其中返回其本身,而不是它的子視圖。

    • 確定多點(diǎn)觸摸序列中最后一個(gè)手指何時(shí)離開

      當(dāng)您希望知道一個(gè)多點(diǎn)觸摸序列中的最后一個(gè)手指何時(shí)從視圖離開時(shí),可以將傳入的集合參數(shù)中包含的UITouch對(duì)象數(shù)量和UIEvent參數(shù)對(duì)象中與該視圖關(guān)聯(lián)的觸摸對(duì)象數(shù)量相比較。請(qǐng)看下面的例子:

      - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
      if ([touches count] == [[event touchesForView:self] count]) {
      // last finger has lifted....
      }
      }

    ?

    看完文檔我們也許還不能完全掌握ios觸摸事件,下面我們結(jié)合一個(gè)實(shí)例來繼續(xù)學(xué)習(xí)。

    新建一個(gè)項(xiàng)目SwitchByGesture,添加一個(gè)UIViewController命名為SecondViewController。

    在ViewController.m中添加下面代碼:

    ?


    我們實(shí)現(xiàn)了touchBegan方法,在該方法中我們記住觸摸事件其實(shí)坐標(biāo),在touchEnded方法中我們獲取手勢結(jié)束時(shí)的坐標(biāo),接著判斷是否符合我們的條件(即水平向左滑動(dòng)且上下滑動(dòng)不超過10),如果符合切換視圖。

    ?

    接著同樣我們要在SecondViewController.m中實(shí)現(xiàn)上述兩個(gè)方法只不過判斷條件不同如下:

    ?


    即水平向右滑動(dòng),切換原來的視圖。編譯運(yùn)行,如果不出意外的話,會(huì)出現(xiàn)下面的效果:

    ?

    向左滑動(dòng)

    ?

    向右滑動(dòng)


    ?

    好了就寫這么多,有什么問題請(qǐng)留言,大家一起學(xué)習(xí)交流!





    轉(zhuǎn)載于:https://www.cnblogs.com/jackljf/archive/2012/09/11/3589303.html

    總結(jié)

    以上是生活随笔為你收集整理的移动开发:iphone开发之触摸事件详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。