UI進(jìn)階12 觸摸事件

觸摸事件

iOS中的事件

  • 在用戶(hù)使用app過(guò)程中,會(huì)產(chǎn)生各種各樣的事件
  • iOS中的事件可以分為3大類(lèi)型:觸摸事件,加速計(jì)事件,遠(yuǎn)程控制事件

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

  • 在iOS中不是任何對(duì)象都能處理事件榴芳,只有繼承了UIResponder的對(duì)象才能接收并處理事件。我們稱(chēng)之為“響應(yīng)者對(duì)象”

  • UIApplication跺撼、UIViewController窟感、UIView都繼承自UIResponder,因此它們都是響應(yīng)者對(duì)象财边,都能夠接收并處理事件

UIResponder

  • UIResponder內(nèi)部提供了以下方法來(lái)處理事件
    - 觸摸事件
- (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;
    - 加速計(jì)事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
    - 遠(yuǎn)程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event

UIView的觸摸事件處理

  • UIView是UIResponder的子類(lèi),可以覆蓋下列4個(gè)方法處理不同的觸摸事件
  • 一根或者多根手指開(kāi)始觸摸view点骑,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法
     - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  • 一根或者多根手指在view上移動(dòng)酣难,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法(隨著手指的移動(dòng),會(huì)持續(xù)調(diào)用該方法)
     - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- 一根或者多根手指離開(kāi)view黑滴,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法
     - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- 觸摸結(jié)束前憨募,某個(gè)系統(tǒng)事件(例如電話呼入)會(huì)打斷觸摸過(guò)程,系統(tǒng)會(huì)自動(dòng)調(diào)用view的下面方法
     - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

提示:touches中存放的都是UITouch對(duì)象

UITouch

  • 當(dāng)用戶(hù)用一根手指觸摸屏幕時(shí)袁辈,會(huì)創(chuàng)建一個(gè)與手指相關(guān)聯(lián)的UITouch對(duì)象

  • 一根手指對(duì)應(yīng)一個(gè)UITouch對(duì)象

  • UITouch的作用

    • 保存著跟手指相關(guān)的信息菜谣,比如觸摸的位置、時(shí)間晚缩、階段
  • 當(dāng)手指移動(dòng)時(shí)尾膊,系統(tǒng)會(huì)更新同一個(gè)UITouch對(duì)象,使之能夠一直保存該手指在的觸摸位置

  • 當(dāng)手指離開(kāi)屏幕時(shí)荞彼,系統(tǒng)會(huì)銷(xiāo)毀相應(yīng)的UITouch對(duì)象

  • 提示:iPhone開(kāi)發(fā)中冈敛,要避免使用雙擊事件!

UITouch的屬性

  • 觸摸產(chǎn)生時(shí)所處的窗口
@property(nonatomic,readonly,retain) UIWindow    *window;
  • 觸摸產(chǎn)生時(shí)所處的視圖
@property(nonatomic,readonly,retain) UIView      *view;
  • 短時(shí)間內(nèi)點(diǎn)按屏幕的次數(shù)鸣皂,可以根據(jù)tapCount判斷單擊抓谴、雙擊或更多的點(diǎn)擊
@property(nonatomic,readonly) NSUInteger          tapCount;
  • 記錄了觸摸事件產(chǎn)生或變化時(shí)的時(shí)間暮蹂,單位是秒
@property(nonatomic,readonly) NSTimeInterval      timestamp;
  • 當(dāng)前觸摸事件所處的狀態(tài)
@property(nonatomic,readonly) UITouchPhase        phase;
UITouchPhase是一個(gè)枚舉類(lèi)型,包含:
UITouchPhaseBegan(觸摸開(kāi)始)
UITouchPhaseMoved(接觸點(diǎn)移動(dòng))
UITouchPhaseStationary(接觸點(diǎn)無(wú)移動(dòng))
UITouchPhaseEnded(觸摸結(jié)束)
UITouchPhaseCancelled(觸摸取消)

UITouch的方法

  • (CGPoint)locationInView:(UIView *)view;

    • 返回值表示觸摸在view上的位置
    • 這里返回的位置是針對(duì)view的坐標(biāo)系的(以view的左上角為原點(diǎn)(0, 0))
    • 調(diào)用時(shí)傳入的view參數(shù)為nil的話癌压,返回的是觸摸點(diǎn)在UIWindow的位置
  • (CGPoint)previousLocationInView:(UIView *)view;

    • 該方法記錄了前一個(gè)觸摸點(diǎn)的位置

UIEvent

  • 每產(chǎn)生一個(gè)事件仰泻,就會(huì)產(chǎn)生一個(gè)UIEvent對(duì)象

  • UIEvent:稱(chēng)為事件對(duì)象,記錄事件產(chǎn)生的時(shí)刻和類(lèi)型

  • 常見(jiàn)屬性

    • 事件類(lèi)型
@property(nonatomic,readonly) UIEventType     type;
@property(nonatomic,readonly) UIEventSubtype  subtype;
  • 事件產(chǎn)生的時(shí)間
@property(nonatomic,readonly) NSTimeInterval  timestamp;
  • UIEvent還提供了相應(yīng)的方法可以獲得在某個(gè)view上面的觸摸對(duì)象(UITouch)

touches和event參數(shù)

  • 一次完整的觸摸過(guò)程滩届,會(huì)經(jīng)歷3個(gè)狀態(tài):

    • 觸摸開(kāi)始:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    • 觸摸移動(dòng):- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    • 觸摸結(jié)束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    • 觸摸取消(可能會(huì)經(jīng)歷):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
  • 4個(gè)觸摸事件處理方法中集侯,都有NSSet *touches和UIEvent *event兩個(gè)參數(shù)

    • 一次完整的觸摸過(guò)程中,只會(huì)產(chǎn)生一個(gè)事件對(duì)象丐吓,4個(gè)觸摸方法都是同一個(gè)event參數(shù)
    • 如果兩根手指同時(shí)觸摸一個(gè)view浅悉,那么view只會(huì)調(diào)用一次touchesBegan:withEvent:方法,touches參數(shù)中裝著2個(gè)UITouch對(duì)象
    • 如果這兩根手指一前一后分開(kāi)觸摸同一個(gè)view券犁,那么view會(huì)分別調(diào)用2次touchesBegan:withEvent:方法术健,并且每次調(diào)用時(shí)的touches參數(shù)中只包含一個(gè)UITouch對(duì)象
    • 根據(jù)touches中UITouch的個(gè)數(shù)可以判斷出是單點(diǎn)觸摸還是多點(diǎn)觸摸

事件的產(chǎn)生和傳遞

  • 發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中

  • UIApplication會(huì)從事件隊(duì)列中取出最前面的事件粘衬,并將事件分發(fā)下去以便處理荞估,通常,先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)

  • 主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來(lái)處理觸摸事件稚新,這也是整個(gè)事件處理過(guò)程的第一步

  • 找到合適的視圖控件后勘伺,就會(huì)調(diào)用視圖控件的touches方法來(lái)作具體的事件處理

    • touchesBegan…
    • touchesMoved…
    • touchedEnded…

UIView不接收觸摸事件的三種情況

  • 不接收用戶(hù)交互
userInteractionEnabled = NO
  • 隱藏
hidden = YES
  • 透明
alpha = 0.0 ~ 0.01
  • 提示:UIImageView的userInteractionEnabled默認(rèn)就是NO,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的

觸摸事件處理的詳細(xì)過(guò)程

  • 用戶(hù)點(diǎn)擊屏幕后產(chǎn)生的一個(gè)觸摸事件褂删,經(jīng)過(guò)一系列的傳遞過(guò)程后飞醉,會(huì)找到最合適的視圖控件來(lái)處理這個(gè)事件

  • 找到最合適的視圖控件后,就會(huì)調(diào)用控件的touches方法來(lái)作具體的事件處理

    • touchesBegan…
    • touchesMoved…
    • touchedEnded…
  • 這些touches方法的默認(rèn)做法是將事件順著響應(yīng)者鏈條向上傳遞屯阀,將事件交給上一個(gè)響應(yīng)者進(jìn)行處理

響應(yīng)者鏈條

  • 響應(yīng)者鏈條:是由多個(gè)響應(yīng)者對(duì)象連接起來(lái)的鏈條
  • 作用:能很清楚的看見(jiàn)每個(gè)響應(yīng)者之間的聯(lián)系缅帘,并且可以讓一個(gè)事件多個(gè)對(duì)象處理。
  • 響應(yīng)者對(duì)象:能處理事件的對(duì)象

事件傳遞的完整過(guò)程

  • 1> 先將事件對(duì)象由上往下傳遞(由父控件傳遞給子控件)难衰,找到最合適的控件來(lái)處理這個(gè)事件钦无。

  • 2> 調(diào)用最合適控件的touches….方法

  • 3> 如果調(diào)用了[super touches….];就會(huì)將事件順著響應(yīng)者鏈條往上傳遞,傳遞給上一個(gè)響應(yīng)者

  • 4> 接著就會(huì)調(diào)用上一個(gè)響應(yīng)者的touches….方法

  • *如何判斷上一個(gè)響應(yīng)者
  • 1> 如果當(dāng)前這個(gè)view是控制器的view,那么控制器就是上一個(gè)響應(yīng)者
  • 2> 如果當(dāng)前這個(gè)view不是控制器的view,那么父控件就是上一個(gè)響應(yīng)者

響應(yīng)者鏈的事件傳遞過(guò)程

  • 如果view的控制器存在盖袭,就傳遞給控制器失暂;如果控制器不存在斯嚎,則將其傳遞給它的父視圖
  • 在視圖層次結(jié)構(gòu)的最頂級(jí)視圖挣轨,如果也不能處理收到的事件或消息胞此,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理
  • 如果window對(duì)象也不處理隙券,則其將事件或消息傳遞給UIApplication對(duì)象
  • 如果UIApplication也不能處理該事件或消息固阁,則將其丟棄

監(jiān)聽(tīng)觸摸事件的做法

  • 如果想監(jiān)聽(tīng)一個(gè)view上面的觸摸事件迂卢,之前的做法是

    • 自定義一個(gè)view
    • 實(shí)現(xiàn)view的touches方法溜哮,在方法內(nèi)部實(shí)現(xiàn)具體處理代碼
  • 通過(guò)touches方法監(jiān)聽(tīng)view觸摸事件屿良,有很明顯的幾個(gè)缺點(diǎn)

    • 必須得自定義view
    • 由于是在view內(nèi)部的touches方法中監(jiān)聽(tīng)觸摸事件悠栓,因此默認(rèn)情況下霉涨,無(wú)法讓其他外界對(duì)象監(jiān)聽(tīng)view的觸摸事件
    • 不容易區(qū)分用戶(hù)的具體手勢(shì)行為
  • iOS 3.2之后按价,蘋(píng)果推出了手勢(shì)識(shí)別功能(Gesture Recognizer),在觸摸事件處理方面笙瑟,大大簡(jiǎn)化了開(kāi)發(fā)者的開(kāi)發(fā)難度

UIGestureRecognizer

  • 為了完成手勢(shì)識(shí)別楼镐,必須借助于手勢(shì)識(shí)別器----UIGestureRecognizer

  • 利用UIGestureRecognizer,能輕松識(shí)別用戶(hù)在某個(gè)view上面做的一些常見(jiàn)手勢(shì)

  • UIGestureRecognizer是一個(gè)抽象類(lèi)往枷,定義了所有手勢(shì)的基本行為框产,使用它的子類(lèi)才能處理具體的手勢(shì)

    • UITapGestureRecognizer(敲擊)
    • UIPinchGestureRecognizer(捏合,用于縮放)
    • UIPanGestureRecognizer(拖拽)
    • UISwipeGestureRecognizer(輕掃)
    • UIRotationGestureRecognizer(旋轉(zhuǎn))
    • UILongPressGestureRecognizer(長(zhǎng)按)

UITapGestureRecognizer

  • 每一個(gè)手勢(shì)識(shí)別器的用法都差不多错洁,比如UITapGestureRecognizer的使用步驟如下
    • 創(chuàng)建手勢(shì)識(shí)別器對(duì)象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
  • 設(shè)置手勢(shì)識(shí)別器對(duì)象的具體屬性
// 連續(xù)敲擊2次
tap.numberOfTapsRequired = 2;
// 需要2根手指一起敲擊
tap.numberOfTouchesRequired = 2;
  • 添加手勢(shì)識(shí)別器到對(duì)應(yīng)的view上
[self.iconView addGestureRecognizer:tap];
  • 監(jiān)聽(tīng)手勢(shì)的觸發(fā)
[tap addTarget:self action:@selector(tapIconView:)];

手勢(shì)識(shí)別的狀態(tài)

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    // 沒(méi)有觸摸事件發(fā)生秉宿,所有手勢(shì)識(shí)別的默認(rèn)狀態(tài)
    UIGestureRecognizerStatePossible,
    // 一個(gè)手勢(shì)已經(jīng)開(kāi)始但尚未改變或者完成時(shí)
    UIGestureRecognizerStateBegan,
    // 手勢(shì)狀態(tài)改變
    UIGestureRecognizerStateChanged,
    // 手勢(shì)完成
    UIGestureRecognizerStateEnded,
    // 手勢(shì)取消,恢復(fù)至Possible狀態(tài)
    UIGestureRecognizerStateCancelled,
    // 手勢(shì)失敗屯碴,恢復(fù)至Possible狀態(tài)
    UIGestureRecognizerStateFailed,
    // 識(shí)別到手勢(shì)識(shí)別
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末描睦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子导而,更是在濱河造成了極大的恐慌忱叭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件今艺,死亡現(xiàn)場(chǎng)離奇詭異韵丑,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)虚缎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)撵彻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人实牡,你說(shuō)我怎么就攤上這事陌僵。” “怎么了铲掐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵拾弃,是天一觀的道長(zhǎng)值桩。 經(jīng)常有香客問(wèn)我摆霉,道長(zhǎng),這世上最難降的妖魔是什么奔坟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任携栋,我火速辦了婚禮,結(jié)果婚禮上咳秉,老公的妹妹穿的比我還像新娘婉支。我一直安慰自己,他們只是感情好澜建,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布向挖。 她就那樣靜靜地躺著蝌以,像睡著了一般。 火紅的嫁衣襯著肌膚如雪何之。 梳的紋絲不亂的頭發(fā)上跟畅,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音溶推,去河邊找鬼徊件。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蒜危,可吹牛的內(nèi)容都是我干的虱痕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辐赞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼部翘!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起占拍,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤略就,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后晃酒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體表牢,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年贝次,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了崔兴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛔翅,死狀恐怖敲茄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情山析,我是刑警寧澤堰燎,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站笋轨,受9級(jí)特大地震影響秆剪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爵政,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一仅讽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钾挟,春花似錦洁灵、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苫费。三九已至,卻和暖如春双抽,著一層夾襖步出監(jiān)牢的瞬間黍衙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工荠诬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琅翻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓柑贞,卻偏偏與公主長(zhǎng)得像方椎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钧嘶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容