Typist:iOS上簡潔的鍵盤監(jiān)聽庫

前言

在iOS想要監(jiān)聽鍵盤的話是通過注冊通知、接收鍵盤發(fā)來的通知實現(xiàn)的爽航,雖然步驟不是很多横浑,不過由于鍵盤的狀態(tài)很多(有6種),如果需求要監(jiān)聽所有的狀態(tài)腻暮,想想你要把相同的代碼寫6次彤守,是有多煩人毯侦。而且適配的系統(tǒng)在iOS 9以下還要把一個個通知移除。這是有多不簡潔...不過自從我遇到了Typist, 感覺優(yōu)雅簡潔到要死具垫。

Typist簡介

Typist is a small, drop-in Swift UIKit keyboard manager for iOS apps. It helps you manage keyboard's screen presence and behavior without notification center and Objective-C.

也就是說Typist主要方便了鍵盤顯示的事件侈离,那么他究竟是怎么方便的呢?下面這段代碼就是Typist的簡單使用:

 let keyboard = Typist.shared
keyboard
    .on(event: .didShow) { (options) in
        print("New Keyboard Frame is \(options.endFrame).")
    }
    .on(event: .didHide) { (options) in
        print("It took \(options.animationDuration) seconds to animate keyboard out.")
    }
    .start()

Oh, my god.怎么看上去和Rx有點像呀筝蚕。哈哈卦碾,確實是的,不過這里作者只是運用了方法的鏈式調(diào)用起宽。并沒有Rx那么高大上哈洲胖。
如何你想要移除鍵盤監(jiān)聽,那么直接調(diào)用keyboard.clear()即可坯沪。
不過這里有點需要注意下绿映,當有多個不同的對象都要監(jiān)聽鍵盤時,不要使用該單例腐晾。也就說這種情況下就需要你自己去創(chuàng)建Typist對象了叉弦,不要使用Typist.shared這個會導致你其中某些對象接受不到通知。

從鍵盤監(jiān)聽說起

在不使用Typist的情況下藻糖,我們是怎么做鍵盤監(jiān)聽的呢淹冰?


具體步驟如圖所示。不過在如果你的應(yīng)用支持iOS 9+以上颖御,那么就可以不用去移除通知榄棵,這個在Apple文檔里也有說明。
可能只是一張圖你看不出來有多煩人潘拱,那么我用代碼演示下是這樣的疹鳄。

而且這僅僅只是監(jiān)聽了鍵盤的實現(xiàn)方法,就已經(jīng)需要這么多代碼了芦岂。那么我們要是遇到需求要監(jiān)聽所有的鍵盤通知呢瘪弓?那么上面代碼就成了這樣:

一堆樣式相同的模板代碼,有人會說禽最,我需要一個函數(shù)封裝下腺怯,不過還是還是不夠Typist簡潔。

那么Typiest是如何做鍵盤監(jiān)聽的

let keyboard = Typist.shared // #1
 
keyboard
    .on(event: .didShow) { (options) in // #2
        print("New Keyboard Frame is \(options.endFrame).")
    }
    .on(event: .didHide) { (options) in // #3
        print("It took \(options.animationDuration) seconds to animate keyboard out.")
    }
    .start() // #4

還是從簡介中的這段代碼說起川无,#1處是使用單例創(chuàng)建一個Typist對象呛占;#2 處監(jiān)聽了鍵盤顯示結(jié)束,閉包回調(diào)里的options包含了一些鍵盤信息懦趋,也就是NotificationCenter里面的info信息晾虑;#3 處監(jiān)聽了鍵盤的隱藏結(jié)束,閉包回調(diào)同上;#4 在這里開始監(jiān)聽帜篇,相當與我們使用的addobserver: 方法糙捺。
具體的邏輯如下圖所示:


那么它內(nèi)部究竟是怎么做的呢?

public func on(event: KeyboardEvent, do callback: TypistCallback?) -> Self 方法

這個方式的實現(xiàn)很簡單笙隙,僅僅是將callbac回調(diào)放入一個dict里面洪灯,dict的key是event,然后返回自己竟痰。

public func on(event: KeyboardEvent, do callback: TypistCallback?) -> Self {
        callbacks[event] = callback
        return self
}

KeyboardEvent

作者在這里定義了一個枚舉來封裝了各個不同的鍵盤監(jiān)聽签钩,然后我們在on方法里直接用傳入枚舉值就可以。

public enum KeyboardEvent {
    /// Event raised by UIKit's `.UIKeyboardWillShow`.
    case willShow
        
    /// Event raised by UIKit's `.UIKeyboardDidShow`.
    case didShow
        
    /// Event raised by UIKit's `.UIKeyboardWillShow`.
    case willHide
        
    /// Event raised by UIKit's `.UIKeyboardDidHide`.
    case didHide
        
    /// Event raised by UIKit's `.UIKeyboardWillChangeFrame`.
    case willChangeFrame
        
    /// Event raised by UIKit's `.UIKeyboardDidChangeFrame`.
    case didChangeFrame
}

start 方法

start在這里僅僅是注冊了鍵盤通知凯亮,注意下addObserver方法的參數(shù)边臼。這里的event就是上面的KeyboardEvent,通過event映射到NSNotification.Name 和 SEL假消。

/// Starts listening to events and calling corresponding events handlers.
    public func start() {
        let center = NotificationCenter.`default`
        
        for event in callbacks.keys {
            center.addObserver(self, selector: event.selector, name: event.notification, object: nil)
        }
    }

event.selector 與 event.notification 屬性

這兩個KeyboardEvent擴展下的私有屬性分別返回上面提到的 NSNotification.Name 和 SEL

fileprivate extension Typist.KeyboardEvent {
    var notification: NSNotification.Name {
        get {
            switch self {
            case .willShow:
                return .UIKeyboardWillShow
            case .didShow:
                return .UIKeyboardDidShow
            case .willHide:
                return .UIKeyboardWillHide
            case .didHide:
                return .UIKeyboardDidHide
            case .willChangeFrame:
                return .UIKeyboardWillChangeFrame
            case .didChangeFrame:
                return .UIKeyboardDidChangeFrame
            }
        }
    }
    
    var selector: Selector {
        get {
            switch self {
            case .willShow:
                return #selector(Typist.keyboardWillShow(note:))
            case .didShow:
                return #selector(Typist.keyboardDidShow(note:))
            case .willHide:
                return #selector(Typist.keyboardWillHide(note:))
            case .didHide:
                return #selector(Typist.keyboardDidHide(note:))
            case .willChangeFrame:
                return #selector(Typist.keyboardWillChangeFrame(note:))
            case .didChangeFrame:
                return #selector(Typist.keyboardDidChangeFrame(note:))
            }
        }
    }
}

SEL 在哪里實現(xiàn)

關(guān)于上面的event.selector是如何實現(xiàn)調(diào)用的柠并。實際上是通過閉包的形式調(diào)用,作者在這里實現(xiàn)了每一個的監(jiān)聽響應(yīng)方法富拗,然后在該方法里去調(diào)用閉包來做臼予。具體閉包的實現(xiàn)是使用者來實現(xiàn)的,然后通過key為event的dict來獲取閉包啃沪。
舉例代碼:

internal func keyboardWillShow(note: Notification) {
    if let callback = callbacks[.willShow] {
        callback(keyboardOptions(fromNotificationDictionary: note.userInfo))
    }
}

KeyboardOptions

這里主要是一些與鍵盤有關(guān)的信息粘拾。


總結(jié)

簡單總結(jié)下該優(yōu)雅的邏輯:

  1. let keyboard = Typist.shared
  2. 調(diào)用func on(event: KeyboardEvent, do callback: TypistCallback?),
    • 該方法中僅僅做了一件事:callbacks[event] = callback
    • 顯然這個閉包是我們?nèi)崿F(xiàn)的。
  3. 調(diào)用start()方法
    • 遍歷了callbacks, 依次實現(xiàn)了addObserve方法创千,主要兩個參數(shù)是selector: event.selector, name: event.notification
    • 其中event.notification event 和keyboard NSNotification.Name 的映射, event.selector中去調(diào)用了callbacks中的閉包缰雇,也就是我們的實現(xiàn)事件。
  4. 可以調(diào)用stop()方法移除通知追驴。
    • 本質(zhì)上是調(diào)用了removeObserver方法.

參考

Typist GitHub Repo
原文地址:https://vsccw.com/2017/02/26/for-typist/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末械哟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子殿雪,更是在濱河造成了極大的恐慌暇咆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丙曙,死亡現(xiàn)場離奇詭異爸业,居然都是意外死亡,警方通過查閱死者的電腦和手機亏镰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門扯旷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人索抓,你說我怎么就攤上這事钧忽∧匙ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵惰瓜,是天一觀的道長。 經(jīng)常有香客問我汉矿,道長崎坊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任洲拇,我火速辦了婚禮奈揍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赋续。我一直安慰自己男翰,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布纽乱。 她就那樣靜靜地躺著蛾绎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸦列。 梳的紋絲不亂的頭發(fā)上租冠,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音薯嗤,去河邊找鬼顽爹。 笑死,一個胖子當著我的面吹牛骆姐,可吹牛的內(nèi)容都是我干的镜粤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼玻褪,長吁一口氣:“原來是場噩夢啊……” “哼肉渴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起归园,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤黄虱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后庸诱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捻浦,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年桥爽,在試婚紗的時候發(fā)現(xiàn)自己被綠了朱灿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡钠四,死狀恐怖盗扒,靈堂內(nèi)的尸體忽然破棺而出跪楞,到底是詐尸還是另有隱情,我是刑警寧澤侣灶,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布甸祭,位于F島的核電站,受9級特大地震影響褥影,放射性物質(zhì)發(fā)生泄漏池户。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一凡怎、第九天 我趴在偏房一處隱蔽的房頂上張望校焦。 院中可真熱鬧,春花似錦统倒、人聲如沸寨典。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耸成。三九已至,卻和暖如春浴鸿,著一層夾襖步出監(jiān)牢的瞬間墓猎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工赚楚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毙沾,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓宠页,卻偏偏與公主長得像左胞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子举户,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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