2017-07-30 21 views
5

Hướng dẫn bố cục khu vực an toàn mới được giới thiệu trong iOS 11 hoạt động tuyệt vời để ngăn nội dung hiển thị bên dưới thanh nhưng không bao gồm bàn phím. Điều đó có nghĩa là khi bàn phím được hiển thị, nội dung vẫn bị ẩn đằng sau nó và đây là vấn đề tôi đang cố giải quyết.Mở rộng Khu vực an toàn cho iOS 11 để bao gồm bàn phím

Cách tiếp cận của tôi dựa trên việc nghe thông báo bàn phím và sau đó điều chỉnh khu vực an toàn thông qua additionalSafeAreaInsets.

Đây là mã của tôi:

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(); 
     } 
    } 
} 

này hoạt động tốt như MyController là một UIViewController với một UITableView mà kéo dài qua toàn bộ khu vực an toàn. Bây giờ khi bàn phím xuất hiện, phần dưới được đẩy lên sao cho không có ô nào nằm phía sau bàn phím.

Vấn đề là với thanh đáy. Tôi cũng có một thanh công cụ ở phía dưới đã được bao gồm trong khu vực an toàn. Vì vậy, thiết lập chiều cao bàn phím đầy đủ như chèn thêm khu vực an toàn đẩy dưới cùng của bảng xem lên quá nhiều bởi chính xác chiều cao của thanh dưới cùng. Để phương pháp này hoạt động tốt, tôi phải đặt additionalSafeAreaInsets.bottom bằng với chiều cao bàn phím trừ đi độ cao của thanh dưới cùng.

Câu hỏi 1: Cách tốt nhất để có khoảng cách khu vực an toàn hiện tại ở dưới cùng là gì? Thủ công có được khung thanh công cụ và sử dụng chiều cao của nó? Hoặc có thể lấy khoảng cách trực tiếp từ hướng dẫn bố trí khu vực an toàn không?

Câu hỏi 2: Có lẽ nó có thể cho thanh dưới cùng thay đổi kích thước mà không có kích thước bàn phím thay đổi vì vậy tôi cũng nên thực hiện một số phương pháp nghe thay đổi trong khung của thanh. Điều này có được thực hiện tốt nhất trong viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) không? Hoặc ở nơi khác?

Cảm ơn bạn

Trả lời

6

gì dường như được làm việc đối với tôi là để tính toán các giao lộ giữa view.safeAreaLayoutGuide.layoutFrame và khung bàn phím, và sau đó thiết lập chiều cao đó là additionalSafeAreaInsets.bottom, thay vì toàn bộ chiều cao khung bàn phím. Tôi không có một thanh công cụ trong bộ điều khiển xem của tôi, nhưng tôi có một thanh tab và nó được tính toán chính xác.

mã hoàn chỉnh:

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

Đó là giải pháp tốt hơn để đối phó với iPhoneX, vì chiều cao của nó bao gồm bên ngoài khu vực an toàn –

+0

... nhưng tiếc là nó sử dụng safeAreaLayoutGuide, chỉ có iOS11 và tôi cần hỗ trợ lại cho iOS9 –

+0

Bạn không gặp bất kỳ sự cố nào với điều này và iPhone X phải không? Vị trí Y của bàn phím, khi được hiển thị trên iPhone X, có vẻ hơi quá cao so với màn hình thực tế. – Jonny

3

Nếu bạn cần hỗ trợ trở lại mức trước IOS11 phiên bản bạn có thể sử dụng chức năng từ Fabio và thêm:

if #available(iOS 11.0, *) { } 

giải pháp cuối cùng:

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) 
     } 
    } 
} 
Các vấn đề liên quan