Extend iOS 11 Safe Area to include the keyboard

后端 未结 5 711
忘了有多久
忘了有多久 2020-12-25 14:53

The new Safe Area layout guide introduced in iOS 11 works great to prevent content from displaying below bars, but it excludes the keyboard. That means that when a keyboard

5条回答
  •  时光取名叫无心
    2020-12-25 15:23

    What seems to be working for me is to calculate the intersection between view.safeAreaLayoutGuide.layoutFrame and the keyboard frame, and then setting the height of that as the additionalSafeAreaInsets.bottom, instead of the whole keyboard frame height. I don't have a toolbar in my view controller, but I do have a tab bar and it is accounted for correctly.

    Complete code:

    import UIKit
    
    public extension UIViewController 
    {
        func startAvoidingKeyboard() 
        {    
            NotificationCenter.default
                .addObserver(self,
                             selector: #selector(onKeyboardFrameWillChangeNotificationReceived(_:)),
                             name: UIResponder.keyboardWillChangeFrameNotification,
                             object: nil)
        }
    
        func stopAvoidingKeyboard() 
        {
            NotificationCenter.default
                .removeObserver(self,
                                name: UIResponder.keyboardWillChangeFrameNotification,
                                object: nil)
        }
    
        @objc
        private func onKeyboardFrameWillChangeNotificationReceived(_ notification: Notification) 
        {
            guard 
                let userInfo = notification.userInfo,
                let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] 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 keyboardAnimationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey]
            let animationDuration: TimeInterval = (keyboardAnimationDuration as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
            let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw)
    
            UIView.animate(withDuration: animationDuration,
                           delay: 0,
                           options: animationCurve,
                           animations: {
                self.additionalSafeAreaInsets.bottom = intersection.height
                self.view.layoutIfNeeded()
            }, completion: nil)
        }
    }
    

提交回复
热议问题