1、問題背景
在研究使用IQKeyBoardManager來處理鍵盤的彈出和放下等一些列事件的時候,頁面使用的是UITableView,并在cell中繪制了多個文本輸入框。由于項(xiàng)目是基于UINavigationController建立的,當(dāng)鍵盤彈出時發(fā)現(xiàn)navigationBar 被自動隱藏了。等到鍵盤放下后navigationBar卻沒有像期望的那樣重新回到當(dāng)初的位置。第一感覺是不是使用了IQKeyBoardManager,而IQKeyBoardManager在處理鍵盤遮擋的時候更改了navigationbar的位置,照著這個想法隨便研究了一下IQKeyBoardManager。
2、IQKeyBoardManager 設(shè)計思想及加載過程
它繼承自NSObject,設(shè)計的方案是作為一個單例來加載,并且實(shí)現(xiàn)了NSObject 的類方法 load 來完成初始化,由于他采用的機(jī)制是將Manager作為鍵盤、設(shè)備方向相關(guān)事件的觀察者,并且基于響應(yīng)者當(dāng)前界面的響應(yīng)者鏈完成了相關(guān)控件的管理。
3、問題的最終確診及解決方案
各種嘗試更改IQKeyBoardManager在處理鍵盤彈出等事件相關(guān)方法都無果后,做了個移除IQKeyBoardManager的測試。結(jié)果發(fā)現(xiàn)navigationbar依然會被隱藏,經(jīng)過一陣眩暈后發(fā)現(xiàn)原來NavigationController的在IOS8之后新增了如下屬性,閑時還是得多讀書呀……
/// When the keyboard appears, the navigation controller's navigationBar toolbar will be hidden. The bars will remain hidden when the keyboard dismisses, but a tap in the content area will show them.
@available(iOS 8.0, *)
open var hidesBarsWhenKeyboardAppears: Bool
/// When the user swipes, the navigation controller's navigationBar & toolbar will be hidden (on a swipe up) or shown (on a swipe down). The toolbar only participates if it has items.
@available(iOS 8.0, *)
open var hidesBarsOnSwipe: Bool
/// When the UINavigationController's vertical size class is compact, hide the UINavigationBar and UIToolbar. Unhandled taps in the regions that would normally be occupied by these bars will reveal the bars.
@available(iOS 8.0, *)
open var hidesBarsWhenVerticallyCompact: Bool
/// When the user taps, the navigation controller's navigationBar & toolbar will be hidden or shown, depending on the hidden state of the navigationBar. The toolbar will only be shown if it has items to display.
@available(iOS 8.0, *)
open var hidesBarsOnTap: Bool
看第一個屬性的注釋,內(nèi)心有一種放完炮就走的感覺,還好他留下了能解決問題的人,于是將希望寄托在了hidesBarsOnTap屬性上。
單純的通過在keyboard show和hidden時設(shè)置hidesBarsOnTap的true和false并沒有完美的解決我的問題。隨后增加了navigationbar顯示和隱藏的監(jiān)聽。
最終解決方案的代碼如下:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = false
NotificationCenter.default.addObserver(self, selector: #selector(keyboardHidden(notify:)), name:NSNotification.Name.UIKeyboardDidHide , object:nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow(notify:)), name:NSNotification.Name.UIKeyboardDidShow , object:nil)
navigationController?.navigationBar.addObserver(self, forKeyPath: "hidden", options: NSKeyValueObservingOptions.new, context: nil)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.hidesBarsWhenKeyboardAppears = false
navigationController?.hidesBarsOnSwipe = false
navigationController?.hidesBarsWhenVerticallyCompact = false
navigationController?.hidesBarsOnTap = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidHide, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
navigationController?.navigationBar.removeObserver(self, forKeyPath: "hidden", context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "hidden",change != nil {
let flag:Bool = change![NSKeyValueChangeKey.newKey] as! Bool
if flag {
self.navigationController?.hidesBarsOnTap = true
}else{
self.navigationController?.hidesBarsOnTap = false
}
}
}
@objc func keyboardHidden(notify:Notification){
self.navigationController?.hidesBarsOnTap = navigationController?.isNavigationBarHidden == true ? true:false
}
@objc func keyboardShow(notify:Notification){
self.navigationController?.hidesBarsOnTap = true
}
目前的解決方案還不是很完美,歡迎各位留言指正。