iOS 事件傳遞

查找響應(yīng)者

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;

hitTexst

它首先會通過調(diào)用自身的 pointInside 方法判斷用戶觸摸的點是否在當前對象的響應(yīng)范圍內(nèi),如果 pointInside 方法返回 NO hitTest方法直接返回 nil

如果 pointInside 方法返回 YES hitTest方法接著會判斷自身是否有子視圖.如果有則調(diào)用頂層子視圖的 hitTest 方法 直到有子視圖返回 View

如果所有子視圖都返回 nil hitTest 方法返回自身.

img

事件傳遞

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);

1、找到第一響應(yīng)者 application 便會根據(jù) event 調(diào)用第一響應(yīng)者響

2朱监、第一響應(yīng)者在這幾個方法中處理響應(yīng)的事件,處理完成后根據(jù)需要調(diào)用 nextResponder 的 touch 方法,通常 nextResponder 就是第一響應(yīng)者的 superView 文章的第一張圖倒著看就是nextResponder 的順序

事件處理流程

1 當用戶點擊屏幕時焰手,會產(chǎn)生一個觸摸事件,系統(tǒng)會將該事件加入到一個由UIApplication管理的事件隊列中

2 UIApplication會從事件隊列中取出最前面的事件進行分發(fā)以便處理粟按,通常,先發(fā)送事件給應(yīng)用程序的主窗口(UIWindow)

3 主窗口會調(diào)用hitTest:withEvent:方法在視圖(UIView)層次結(jié)構(gòu)中找到一個最合適的UIView來處理觸摸事件
(hitTest:withEvent:其實是UIView的一個方法,UIWindow繼承自UIView布蔗,因此主窗口UIWindow也是屬于視圖的一種)

通常第一響應(yīng)者都是響應(yīng)鏈中最末端的響應(yīng)者,事件攔截就是在響應(yīng)鏈中截獲事件,停止下發(fā).將事件交由中間的某個響應(yīng)者執(zhí)行.比如這樣:

應(yīng)用

1、擴大按鈕的點擊區(qū)域(上下左右各增加20)

重寫按鈕的 pointInside 方法

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(CGRectInset(self.bounds, -20, -20), point)) {
        return YES;
    }
    return NO;
}

2、子view超出了父view的bounds響應(yīng)事件

正常情況下田藐,子View超出父View的bounds的那一部分是不會響應(yīng)事件的右遭。一般解決方案:修改父view的大小

解決方法:重寫父View的pointInside方法,使事件Point 在超出父view的部分返回 true

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL flag = NO;
    for (UIView *view in self.subviews) {
        if (CGRectContainsPoint(view.frame, point)){
            flag = YES;
            break;
        }
    }
    return flag;
}

3滥搭、如果一個Button被一個View蓋住了,在觸摸View時,希望該Button能夠響應(yīng)事件

解決方法1:點擊View及View的非交互子View(例如UIImageView)帚桩,則該Button可以響應(yīng)事件

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL next = YES;
    for (UIView *view in self.subviews) {
        if ([view isKindOfClass:[UIControl class]]) {
            if (CGRectContainsPoint(view.frame, point)){
                next = NO;
                break;
            }
        }
    }
    return !next;
}

解決方法2:點擊View本身Button會響應(yīng)該事件,點擊View的任何一個子View嘹黔,Button不會響應(yīng)事件

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *view = [super hitTest:point withEvent:event];
    if (view == self) {
        return nil;
    }
    return view;
}

4 特殊的UIScrollView

img

該ScrollView可以顯示上一頁和下一頁的部分界面账嚎,紅色框是ScrollView的frame,綠色框部分是設(shè)置了clipsToBounds = NO的結(jié)果儡蔓,但是正如情況2提到的郭蕉,超出部分是不響應(yīng)事件的。

    CGSize size = [UIScreen mainScreen].bounds.size;
    CGFloat width = size.width - 80;
    JCScrollView *scrollView = [[JCScrollView alloc] initWithFrame:CGRectMake(40, size.height - 150 - 30, width, 150)];
    scrollView.pagingEnabled = YES;
    scrollView.clipsToBounds = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.showsHorizontalScrollIndicator = NO;
    [scrollView setContentSize:CGSizeMake(width * 5, 150)];
    
    for (NSInteger i = 0; i < 5; i++) {
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(5 + width * i, 0, width - 10, 150)];
        view.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255) / 255.0f green:arc4random_uniform(255) / 255.0f blue:arc4random_uniform(255) / 255.0f alpha:1];
        [scrollView addSubview:view];
    }
    
    [self.view addSubview:scrollView];

如果需要綠色框響應(yīng)ScrollView的滾動事件喂江,則原理和情況1一樣

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(CGRectInset(self.bounds, -40, 0), point)) {
        return YES;
    }
    return NO;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末召锈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子获询,更是在濱河造成了極大的恐慌涨岁,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吉嚣,死亡現(xiàn)場離奇詭異梢薪,居然都是意外死亡,警方通過查閱死者的電腦和手機尝哆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門秉撇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事畜疾「傲冢” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵啡捶,是天一觀的道長姥敛。 經(jīng)常有香客問我,道長瞎暑,這世上最難降的妖魔是什么彤敛? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮了赌,結(jié)果婚禮上墨榄,老公的妹妹穿的比我還像新娘。我一直安慰自己勿她,他們只是感情好袄秩,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逢并,像睡著了一般之剧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砍聊,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天背稼,我揣著相機與錄音,去河邊找鬼玻蝌。 笑死蟹肘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的俯树。 我是一名探鬼主播帘腹,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼聘萨!你這毒婦竟也來了竹椒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤米辐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后书释,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翘贮,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年爆惧,在試婚紗的時候發(fā)現(xiàn)自己被綠了狸页。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芍耘,靈堂內(nèi)的尸體忽然破棺而出址遇,到底是詐尸還是另有隱情,我是刑警寧澤斋竞,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布倔约,位于F島的核電站,受9級特大地震影響坝初,放射性物質(zhì)發(fā)生泄漏浸剩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一鳄袍、第九天 我趴在偏房一處隱蔽的房頂上張望绢要。 院中可真熱鬧,春花似錦拗小、人聲如沸重罪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剿配。三九已至,卻和暖如春勾栗,著一層夾襖步出監(jiān)牢的瞬間惨篱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工围俘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留砸讳,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓界牡,卻偏偏與公主長得像簿寂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宿亡,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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

  • 用戶以多種方式操縱他們的iOS設(shè)備常遂,例如觸摸屏幕或搖動設(shè)備。 iOS會解釋用戶何時以及如何操作硬件并將此信息傳遞到...
    坤坤同學(xué)閱讀 3,992評論 7 19
  • iOS中的事件 觸摸事件挽荠,加速事件(搖一搖)克胳,遠程控制事件(耳機線控,窗口播放) 以最常見的觸摸事件為例圈匆,當觸摸手...
    你duck不必呀閱讀 1,399評論 0 4
  • 本篇主要講解iOS事件傳遞的整個過程漠另,大部分內(nèi)容翻譯自Apple Developer Guide,原文鏈接 當一個...
    Little_Mango閱讀 1,273評論 4 10
  • 響應(yīng)者對象 在iOS中不是所有對象都能處理事件跃赚,只有繼承UIResponder的對象才能接收并處理事件笆搓,我們稱之為...
    小寶二代閱讀 358評論 0 1
  • 這里主要講解記錄下用戶觸摸點擊手機屏幕后產(chǎn)生的事件是如何派發(fā)傳遞的,如何查找到適合響應(yīng)事件的第一響應(yīng)者控件,以及找...
    喔牛慢慢爬閱讀 1,015評論 0 11