From 17190a23d300e3186914dcd7aa1a7d9e75c94c9c Mon Sep 17 00:00:00 2001 From: Mike Donahue Date: Thu, 20 Feb 2020 16:56:38 -0500 Subject: [PATCH] Support tab bar height --- .../KeyboardLayoutGuide.swift | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/Sources/KeyboardLayoutGuide/KeyboardLayoutGuide.swift b/Sources/KeyboardLayoutGuide/KeyboardLayoutGuide.swift index a694cac..4c64e70 100644 --- a/Sources/KeyboardLayoutGuide/KeyboardLayoutGuide.swift +++ b/Sources/KeyboardLayoutGuide/KeyboardLayoutGuide.swift @@ -1,3 +1,4 @@ + // // Keyboard+LayoutGuide.swift // KeyboardLayoutGuide @@ -18,19 +19,19 @@ extension UIView { static var usingSafeArea = "KeyboardLayoutGuideUsingSafeArea" static var notUsingSafeArea = "KeyboardLayoutGuide" } - + /// A layout guide representing the inset for the keyboard. /// Use this layout guide’s top anchor to create constraints pinning to the top of the keyboard or the bottom of safe area. public var keyboardLayoutGuide: UILayoutGuide { getOrCreateKeyboardLayoutGuide(identifier: Identifiers.usingSafeArea, usesSafeArea: true) } - + /// A layout guide representing the inset for the keyboard. /// Use this layout guide’s top anchor to create constraints pinning to the top of the keyboard or the bottom of the view. public var keyboardLayoutGuideNoSafeArea: UILayoutGuide { getOrCreateKeyboardLayoutGuide(identifier: Identifiers.notUsingSafeArea, usesSafeArea: false) } - + private func getOrCreateKeyboardLayoutGuide(identifier: String, usesSafeArea: Bool) -> UILayoutGuide { if let existing = layoutGuides.first(where: { $0.identifier == identifier }) { return existing @@ -50,14 +51,14 @@ open class KeyboardLayoutGuide: UILayoutGuide { updateButtomAnchor() } } - + private var bottomConstraint: NSLayoutConstraint? - + @available(*, unavailable) public required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + public init(notificationCenter: NotificationCenter = NotificationCenter.default) { super.init() // Observe keyboardWillChangeFrame notifications @@ -68,7 +69,7 @@ open class KeyboardLayoutGuide: UILayoutGuide { object: nil ) } - + internal func setUp() { guard let view = owningView else { return } NSLayoutConstraint.activate( @@ -80,39 +81,51 @@ open class KeyboardLayoutGuide: UILayoutGuide { ) updateButtomAnchor() } - + func updateButtomAnchor() { if let bottomConstraint = bottomConstraint { bottomConstraint.isActive = false } - + guard let view = owningView else { return } - + let viewBottomAnchor: NSLayoutYAxisAnchor if #available(iOS 11.0, *), usesSafeArea { viewBottomAnchor = view.safeAreaLayoutGuide.bottomAnchor } else { viewBottomAnchor = view.bottomAnchor } - + bottomConstraint = bottomAnchor.constraint(equalTo: viewBottomAnchor) bottomConstraint?.isActive = true } - + @objc private func keyboardWillChangeFrame(_ note: Notification) { if var height = note.keyboardHeight, let duration = note.animationDuration { + + let presentedView = UIApplication.topViewController() + + var tabBarHeight: CGFloat = 0 + + if presentedView?.tabBarController?.tabBar.isHidden == false { + tabBarHeight = presentedView?.tabBarController?.tabBar.frame.height ?? 0 + } + if #available(iOS 11.0, *), usesSafeArea, height > 0, let bottom = owningView?.safeAreaInsets.bottom { - height -= bottom + height -= bottom + tabBarHeight } + heightConstraint?.constant = height + if duration > 0.0 { animate(note) } + Keyboard.shared.currentHeight = height } } - + private func animate(_ note: Notification) { if let owningView = self.owningView, @@ -153,6 +166,23 @@ extension Notification { } } +extension UIApplication { + class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { + + if let nav = base as? UINavigationController { + return topViewController(base: nav.visibleViewController) + } else if let tab = base as? UITabBarController { + if let selected = tab.selectedViewController { + return topViewController(base: selected) + } + } else if let presented = base?.presentedViewController { + return topViewController(base: presented) + } + + return base + } +} + // Credits to John Gibb for this nice helper :) // https://stackoverflow.com/questions/1536923/determine-if-uiview-is-visible-to-the-user func isVisible(view: UIView) -> Bool {