不用私有API更米,一行代碼獲取當(dāng)前響應(yīng)鏈的First Responder

前言

在iOS中,當(dāng)發(fā)生事件響應(yīng)時抱环,必須知道由誰來響應(yīng)事件壳快。而UIResponder類就是專門用來響應(yīng)用戶的操作,處理各種事件的镇草,包括觸摸事件(Touch Events)眶痰、運動事件(Motion Events)和遠程控制事件(Remote Control Events)。iOS處理事件的流程將遵循一個不同對象組成的層次結(jié)構(gòu)梯啤,也就是響應(yīng)者鏈(Responder Chain)竖伯,網(wǎng)上目前有很多關(guān)于響應(yīng)者鏈的介紹,這里就不再細講因宇。在響應(yīng)者鏈中非常重要的一個概念就是第一響應(yīng)者(First Responder)七婴,當(dāng)前第一響應(yīng)者負責(zé)響應(yīng)事件,或?qū)⑹录鬟f給下一響應(yīng)者察滑。

在編寫iOS程序時打厘,我們經(jīng)常會遇到需要獲取當(dāng)前的第一響應(yīng)者,例如系統(tǒng)彈出鍵盤時贺辰,我們希望得到當(dāng)前輸入框(也就是第一響應(yīng)者)的Frame户盯,從而調(diào)整視圖避免鍵盤遮擋輸入框。然而UIKit并沒有提供官方的API專門用于該用途饲化。本文將介紹一種非常簡單的且未用到私有API的方法來獲取當(dāng)前第一響應(yīng)者莽鸭。

實現(xiàn)思路

常規(guī)思路

通過遍歷當(dāng)前UIWindow的所有子視圖,從而找到當(dāng)前的第一響應(yīng)者吃靠。這種方法首先需要做非常多的遞歸調(diào)用硫眨,從而判斷所有子視圖,同時當(dāng)前響應(yīng)鏈上的第一響應(yīng)者還有可能是子視圖的ViewController巢块,這種方法也會漏掉礁阁。

使用私有API的思路

使用蘋果的私有API可以很容易地解決這個問題巧号,然而蘋果不會允許使用私有API的App上架App Store,而且私有API很有可能隨時變化氮兵,所以這種方式也很不完美裂逐。

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];

本文的思路

本文的思路用到的核心Public API就是

- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event

蘋果文檔對該API的target參數(shù)的描述如下:

The object to receive the action message. If target is nil, the app sends the message to the first responder, from whence it progresses up the responder chain until it is handled.

從而可知,利用該API泣栈,只要將傳入的target設(shè)置為nil卜高,則系統(tǒng)會自動順著響應(yīng)鏈查找能夠響應(yīng)action的響應(yīng)者。我們只需讓所有UIResponder的子類都響應(yīng)我們自定義的action南片,即可知道當(dāng)前第一響應(yīng)者是哪個對象掺涛。

實現(xiàn)方法

為實現(xiàn)本文的思路,我們需要為UIResponder提供一個Category(objc)或者Extension(swift)疼进。

Objective-C

// UIResponder+WTYFirstResponder.h
#import <UIKit/UIKit.h>

@interface UIResponder (WTYFirstResponder)
//使用時只需要對UIResponder類調(diào)用該類方法即可獲得當(dāng)前第一響應(yīng)者
+ (id)wty_currentFirstResponder;
@end

//  UIResponder+WTYFirstResponder.m
#import "UIResponder+WTYFirstResponder.h"

static __weak id wty_currentFirstResponder;

@implementation UIResponder (WTYFirstResponder)
+ (id)wty_currentFirstResponder {
    wty_currentFirstResponder = nil;
    // 通過將target設(shè)置為nil薪缆,讓系統(tǒng)自動遍歷響應(yīng)鏈
    // 從而響應(yīng)鏈當(dāng)前第一響應(yīng)者響應(yīng)我們自定義的方法
    [[UIApplication sharedApplication] sendAction:@selector(wty_findFirstResponder:) 
                                               to:nil 
                                             from:nil 
                                         forEvent:nil];
    return wty_currentFirstResponder;
}
- (void)wty_findFirstResponder:(id)sender {
    // 第一響應(yīng)者會響應(yīng)這個方法,并且將靜態(tài)變量wty_currentFirstResponder設(shè)置為自己
    wty_currentFirstResponder = self;
}
@end

使用方法

#import "UIResponder+WTYFirstResponder.h"

id firstResponder = [UIResponder wty_firstResponder];

Swift

//  UIResponder+WTYFirstResponder.swift

import UIKit

private weak var wty_currentFirstResponder: AnyObject?

extension UIResponder {

    static func wty_firstResponder() -> AnyObject? {
        wty_currentFirstResponder = nil
        // 通過將target設(shè)置為nil伞广,讓系統(tǒng)自動遍歷響應(yīng)鏈
        // 從而響應(yīng)鏈當(dāng)前第一響應(yīng)者響應(yīng)我們自定義的方法
        UIApplication.shared.sendAction(#selector(wty_findFirstResponder(_:)), to: nil, from: nil, for: nil)
        return wty_currentFirstResponder
    }
    
    func wty_findFirstResponder(_ sender: AnyObject) {
        // 第一響應(yīng)者會響應(yīng)這個方法拣帽,并且將靜態(tài)變量wty_currentFirstResponder設(shè)置為自己
        wty_currentFirstResponder = self
    }
}

使用方法

firstResponder = UIResponder.wty_firstResponder()

思路衍生

如果只希望讓第一響應(yīng)者取消其第一響應(yīng)者的狀態(tài),則可以做如下操作:

Objective-C

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

Swift

 UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)

Github Repo

本文所用的代碼可以在我的Github上找到嚼锄,如果覺得好用的話請并忙點個星星减拭。


本文個人博客地址: http://wty.im/2016/09/22/get-the-first-responder/
Github: https://github.com/wty21cn/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市区丑,隨后出現(xiàn)的幾起案子拧粪,更是在濱河造成了極大的恐慌,老刑警劉巖沧侥,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件可霎,死亡現(xiàn)場離奇詭異,居然都是意外死亡宴杀,警方通過查閱死者的電腦和手機癣朗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旺罢,“玉大人斯棒,你說我怎么就攤上這事≈骶” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵庭惜,是天一觀的道長罩驻。 經(jīng)常有香客問我,道長护赊,這世上最難降的妖魔是什么惠遏? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任砾跃,我火速辦了婚禮,結(jié)果婚禮上节吮,老公的妹妹穿的比我還像新娘抽高。我一直安慰自己,他們只是感情好透绩,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布翘骂。 她就那樣靜靜地躺著,像睡著了一般帚豪。 火紅的嫁衣襯著肌膚如雪碳竟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天狸臣,我揣著相機與錄音莹桅,去河邊找鬼。 笑死烛亦,一個胖子當(dāng)著我的面吹牛诈泼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播煤禽,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铐达,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呜师?” 一聲冷哼從身側(cè)響起娶桦,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汁汗,沒想到半個月后衷畦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡知牌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年祈争,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片角寸。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡菩混,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扁藕,到底是詐尸還是另有隱情沮峡,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布亿柑,位于F島的核電站邢疙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疟游,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一呼畸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颁虐,春花似錦蛮原、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至板熊,卻和暖如春框全,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背干签。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工津辩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人容劳。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓喘沿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竭贩。 傳聞我的和親對象是個殘疾皇子蚜印,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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

  • 一. Hit-Testing 什么是Hit-Testing?對于觸摸事件, window首先會嘗試將事件交給事件觸...
    面糊閱讀 826評論 0 50
  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的?困惑于Cell怎么突然不能點擊了留量?糾結(jié)于如何實現(xiàn)這個奇葩響應(yīng)需求窄赋?亦或是...
    Lotheve閱讀 57,103評論 51 599
  • 在iOS開發(fā)中經(jīng)常會涉及到觸摸事件夸楣。本想自己總結(jié)一下躬络,但是遇到了這篇文章昭躺,感覺總結(jié)的已經(jīng)很到位了赌,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,010評論 4 26
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評論 25 707
  • 作為一個簡書新人厂画,來談如何上首頁似乎有些大言不慚缕粹,在這里稚茅,我只是想就這段時間看過的首頁熱門文章,來談一下自己的小看...
    一之魚閱讀 382評論 2 12