2017-07-30 2 views
5

Der neue Safe Area-Layout-Leitfaden, der in iOS 11 eingeführt wurde, funktioniert hervorragend, um zu verhindern, dass Inhalte unter Balken angezeigt werden, aber die Tastatur wird ausgeschlossen. Das heißt, wenn eine Tastatur angezeigt wird, ist der Inhalt immer noch dahinter verborgen und das ist das Problem, das ich versuche zu lösen.Erweitern iOS 11 Sicherer Bereich für die Tastatur

Mein Ansatz basiert auf dem Abhören von Tastaturbenachrichtigungen und der Anpassung des sicheren Bereichs durch additionalSafeAreaInsets.

Hier ist mein Code:

override func viewDidLoad() { 
    let notificationCenter = NotificationCenter.default 
    notificationCenter.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 
    notificationCenter.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 
    notificationCenter.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) 
} 

//MARK: - Keyboard 
extension MyViewController { 
    @objc func keyboardWillShow(notification: NSNotification) { 
     let userInfo = notification.userInfo! 
     let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height 

     additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) 
     UIView.animate(withDuration: 0.3) { 
      self.view.layoutIfNeeded(); 
     } 
    } 

    @objc func keyboardWillHide(notification: NSNotification) { 
     additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 
     UIView.animate(withDuration: 0.3) { 
      self.view.layoutIfNeeded(); 
     } 
    } 

    @objc func keyboardWillChange(notification: NSNotification) { 
     let userInfo = notification.userInfo! 
     let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height 

     additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) 

     UIView.animate(withDuration: 0.3) { 
      self.view.layoutIfNeeded(); 
     } 
    } 
} 

Dies funktioniert auch die MyController ein UIViewController mit einem UITableView ist, die durch den gesamten sicheren Bereich erstreckt. Wenn nun die Tastatur erscheint, wird der Boden nach oben geschoben, so dass sich keine Zellen hinter der Tastatur befinden.

Das Problem ist mit den unteren Balken. Ich habe auch eine Symbolleiste am unteren Rand, die bereits im sicheren Bereich enthalten ist. Wenn Sie daher die volle Tastaturhöhe als zusätzlichen Sicherheitsbereich einsetzen, wird die Unterseite der Tabellenansicht um genau die Höhe der unteren Leiste zu stark verschoben. Damit diese Methode gut funktioniert, muss der Wert additionalSafeAreaInsets.bottom der Tastaturhöhe minus der Höhe der unteren Leiste entsprechen.

Frage 1: Was ist der beste Weg, um den aktuellen Sicherheitsabstand auf der Unterseite zu bekommen? Manuell Rahmen der Werkzeugleiste erhalten und seine Höhe verwenden? Oder ist es möglich, die Lücke direkt aus dem Layout des sicheren Bereichs zu bekommen?

Frage 2: Vermutlich sollte es für die untere Leiste möglich sein, die Größe zu ändern, ohne dass die Tastatur die Größe ändert, also sollte ich auch eine Methode implementieren, die auf Veränderungen im Rahmen der Leiste hört. Ist dies am besten in viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) getan? Oder woanders?

Danke

Antwort

6

Was für mich zu arbeiten scheint, ist die Kreuzung zwischen view.safeAreaLayoutGuide.layoutFrame und dem Tastaturrahmen zu berechnen und dann die Höhe der Einstellung als additionalSafeAreaInsets.bottom, statt der gesamten Tastatur Rahmenhöhe. Ich habe keine Symbolleiste in meinem View-Controller, aber ich habe eine Tab-Leiste und es wird korrekt berücksichtigt.

komplette Code:

extension UIViewController { 

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

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

    @objc private func _onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification) { 
     guard let userInfo = notification.userInfo, 
      let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { 
       return 
     } 

     let keyboardFrameInView = view.convert(keyboardFrame, from: nil) 
     let safeAreaFrame = view.safeAreaLayoutGuide.layoutFrame.insetBy(dx: 0, dy: -additionalSafeAreaInsets.bottom) 
     let intersection = safeAreaFrame.intersection(keyboardFrameInView) 

     let animationDuration: TimeInterval = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0 
     let animationCurveRawNSN = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber 
     let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue 
     let animationCurve = UIViewAnimationOptions(rawValue: animationCurveRaw) 

     UIView.animate(withDuration: animationDuration, delay: 0, options: animationCurve, animations: { 
      self.additionalSafeAreaInsets.bottom = intersection.height 
      self.view.layoutIfNeeded() 
     }, completion: nil) 
    } 
} 
+0

Das ist eine bessere Lösung, um mit iPhoneX fertig zu werden, da seine Höhe ein ist a außerhalb des sicheren Bereichs –

+0

... aber leider verwendet es safeAreaLayoutGuide, der nur iOS11 ist und ich zurück zu iOS9 unterstützen muss –

+0

Haben Sie keine Probleme mit diesem und iPhone X? Die Y-Position der Tastatur erscheint, wenn sie auf dem iPhone X angezeigt wird, im Vergleich zum tatsächlichen Bildschirm etwas zu hoch. – Jonny

3

Wenn Sie brauchen Unterstützung zurück IOS11 Versionen vorzunehmen können Sie die Funktion von Fabio verwenden und fügen:

if #available(iOS 11.0, *) { } 

Endlösung:

extension UIViewController { 

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

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

    @objc private func _onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification) { 
     if #available(iOS 11.0, *) { 

      guard let userInfo = notification.userInfo, 
       let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { 
        return 
      } 

      let keyboardFrameInView = view.convert(keyboardFrame, from: nil) 
      let safeAreaFrame = view.safeAreaLayoutGuide.layoutFrame.insetBy(dx: 0, dy: -additionalSafeAreaInsets.bottom) 
      let intersection = safeAreaFrame.intersection(keyboardFrameInView) 

      let animationDuration: TimeInterval = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0 
      let animationCurveRawNSN = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber 
      let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue 
      let animationCurve = UIViewAnimationOptions(rawValue: animationCurveRaw) 

      UIView.animate(withDuration: animationDuration, delay: 0, options: animationCurve, animations: { 
       self.additionalSafeAreaInsets.bottom = intersection.height 
       self.view.layoutIfNeeded() 
      }, completion: nil) 
     } 
    } 
}