2017-09-15 112 views
0

您好我正在嘗試使視圖的底部與UIKeyboard的頂部對齊。如何將底部視圖移動到UIKeyboard頂部

更新1:我創建了一個GitHub的項目,如果你想給它一個嘗試:https://github.com/JCzz/KeyboardProject

注:我需要的aView是動態的。

更新2:只是推 - 包括使用框架

我可能一直在尋找這個時間太長,我不能換我周圍的大腦:-)

你知道怎麼樣?

  1. 我該如何知道UIKeyboard是否處於關閉狀態?

  2. 如果UIKeyboard已啓動,那麼如何將它與視圖對齊(attachKeyboardToFrame - 請參閱代碼)。

我發現下面的UIView擴展:

import UIKit 

extension UIView { 

    func bindToKeyboard(){ 
     NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) 
    } 

    func unbindFromKeyboard(){ 
     NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) 
    } 

    @objc 
    func keyboardWillChange(notification: NSNotification) { 

     guard let userInfo = notification.userInfo else { return } 

     let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double 
     let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt 
     let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue 
     let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue 

     // To get the total height of view 
     let topView = UIApplication.shared.windows.last 
     // 
     let attachKeyboardToFrame = Singleton.sharedInstance.attachKeyboardToFrame 
     let global_attachKeyboardToFrame = self.superview?.convert(attachKeyboardToFrame!, to: topView) 

     if (targetFrame.height + attachKeyboardToFrame!.height) > (topView?.frame.height)! { 
      self.frame.origin.y = -targetFrame.origin.y 
     }else{ 

     } 

    } 
} 
+1

至1:使用UIKeyboardWillShow和UIKeyboardWillHide代替UIKeyboardWillChangeFrame – Michael

+0

另一個謎團是當按下鍵盤向下箭頭時不會調用UIKeyboardWillHide。 –

回答

1

您可以通過下面的自動佈局解決方案實現它。

首先,你需要UILayoutGuide將被用來模擬鍵盤意識到底部錨和NSLayoutConstraint將控制這個佈局指南:

fileprivate let keyboardAwareBottomLayoutGuide: UILayoutGuide = UILayoutGuide() 
fileprivate var keyboardTopAnchorConstraint: NSLayoutConstraint! 

viewDidLoad添加keyboardAwareBottomLayoutGuide到視圖,並設置相應的約束上:

self.view.addLayoutGuide(self.keyboardAwareBottomLayoutGuide) 
// this will control keyboardAwareBottomLayoutGuide.topAnchor to be so far from bottom of the bottom as is the height of the presented keyboard 
self.keyboardTopAnchorConstraint = self.view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor, constant: 0) 
self.keyboardTopAnchorConstraint.isActive = true 
self.keyboardAwareBottomLayoutGuide.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor).isActive = true 

然後使用以下行開始聽鍵盤顯示和隱藏:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 

最後,使用下面的方法來控制keyboardAwareBottomLayoutGuide模仿鍵盤:

@objc fileprivate func keyboardWillShowNotification(notification: NSNotification) { 
    updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: false) 
} 

@objc fileprivate func keyboardWillHideNotification(notification: NSNotification) { 
    updateKeyboardAwareBottomLayoutGuide(with: notification, hiding: true) 
} 

fileprivate func updateKeyboardAwareBottomLayoutGuide(with notification: NSNotification, hiding: Bool) { 
    let userInfo = notification.userInfo 

    let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue 
    let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue 

    let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value 

    guard let animDuration = animationDuration, 
     let keybrdEndFrame = keyboardEndFrame, 
     let rawAnimCurve = rawAnimationCurve else { 
      return 
    } 

    let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window) 

    let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16) 
    let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted) 

    // this will move the topAnchor of the keyboardAwareBottomLayoutGuide to height of the keyboard 
    self.keyboardTopAnchorConstraint.constant = hiding ? 0 : convertedKeyboardEndFrame.size.height 

    self.view.setNeedsLayout() 

    UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { 
     self.view.layoutIfNeeded() 
    }, completion: { success in 
     // 
    }) 
} 

現在,這一切的設置,您可以使用自動佈局來約束你的意見keyboardAwareBottomLayoutGuide.topAnchor而不是self.view.layoutMarginsGuide.bottomAnchor(或self.view.bottomAnchor ,無論你使用什麼)。 keyboardAwareBottomLayoutGuide會自動調整到顯示或隱藏的鍵盤。

例子:

uiTextField.bottomAnchor.constraint(equalTo: keyboardAwareBottomLayoutGuide.topAnchor).isActive = true 

編輯:直接設置幀

雖然我強烈建議您使用自動佈局,在情況下,當你無法用此去,直接設置框架可以還一個解決方案。你可以使用相同的原則。在這種方法中,你不需要佈局指南,所以你不需要任何額外的實例屬性。只需使用viewDidLoad來聽通知登記:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 

然後實現,將反應這些通知的方法:

@objc fileprivate func keyboardWillShowNotification(notification: NSNotification) { 
    adjustToKeyboard(with: notification, hiding: false) 
} 

@objc fileprivate func keyboardWillHideNotification(notification: NSNotification) { 
    adjustToKeyboard(with: notification, hiding: true) 
} 

fileprivate func adjustToKeyboard(with notification: NSNotification, hiding: Bool) { 
    let userInfo = notification.userInfo 

    let animationDuration = (userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue 
    let keyboardEndFrame = (userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue 

    let rawAnimationCurve = (userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value 

    guard let animDuration = animationDuration, 
     let keybrdEndFrame = keyboardEndFrame, 
     let rawAnimCurve = rawAnimationCurve else { 
      return 
    } 

    let convertedKeyboardEndFrame = view.convert(keybrdEndFrame, from: view.window) 

    let rawAnimCurveAdjusted = UInt(rawAnimCurve << 16) 
    let animationCurve = UIViewAnimationOptions(rawValue: rawAnimCurveAdjusted) 

    // we will go either up or down depending on whether the keyboard is being hidden or shown 
    let diffInHeight = hiding ? convertedKeyboardEndFrame.size.height : -convertedKeyboardEndFrame.size.height 

    UIView.animate(withDuration: animDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { 
     // this will move the frame of the aView according to the diffInHeight calculated above 
     // of course here you need to set all the frames that would be affected by the keyboard (this is why I prefer using autolayout) 
     self.aView?.frame = (self.aView?.frame.offsetBy(dx: 0, dy: diff))! 

     // of course, you can do anything more complex than just moving the aView up.. 
    }) 
} 

在這兩種情況下,不要忘記註銷觀察的通知,一旦是的viewController deinitialized防止保留循環:

deinit { 
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) 
} 
+0

謝謝。即使這兩種觀點有不同的父母,這種工作是否會奏效 –

+0

有什麼意見?我真的不知道我明白你想說什麼..我的解決方案只創建一個適應鍵盤的人爲錨點..所以不是按照左,右,上,下來佈置視圖,而是根據left,right,top和keyboardAwareBottomLayoutGuide.topAnchor。換句話說,通常使用自動佈局,而不是使用viewController.view.bottomAnchor使用keyboardAwareBottomLayoutGuide.topAnchor。 –

+0

所以無論你想在你的視圖中進行約束,你都會按照通常的方式進行操作,只需使用新的佈局指南而不是靜態view.bottomAnchor –

相關問題