Created
January 25, 2018 15:36
-
-
Save simme/a44cd16f89038cbee8537b89d237386b to your computer and use it in GitHub Desktop.
Extension on UITabBarController for hiding/showing the tab bar.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension UITabBarController { | |
/** | |
Show or hide the tab bar. | |
- Parameter hidden: `true` if the bar should be hidden. | |
- Parameter animated: `true` if the action should be animated. | |
- Parameter transitionCoordinator: An optional `UIViewControllerTransitionCoordinator` to perform the animation | |
along side with. For example during a push on a `UINavigationController`. | |
*/ | |
func setTabBar( | |
hidden: Bool, | |
animated: Bool = true, | |
along transitionCoordinator: UIViewControllerTransitionCoordinator? = nil | |
) { | |
guard isTabBarHidden != hidden else { return } | |
let offsetY = hidden ? tabBar.frame.height : -tabBar.frame.height | |
let endFrame = tabBar.frame.offsetBy(dx: 0, dy: offsetY) | |
let vc: UIViewController? = viewControllers?[selectedIndex] | |
var newInsets: UIEdgeInsets? = vc?.additionalSafeAreaInsets | |
let originalInsets = newInsets | |
newInsets?.bottom -= offsetY | |
/// Helper method for updating child view controller's safe area insets. | |
func set(childViewController cvc: UIViewController?, additionalSafeArea: UIEdgeInsets) { | |
cvc?.additionalSafeAreaInsets = additionalSafeArea | |
cvc?.view.setNeedsLayout() | |
} | |
// Update safe area insets for the current view controller before the animation takes place when hiding the bar. | |
if hidden, let insets = newInsets { set(childViewController: vc, additionalSafeArea: insets) } | |
guard animated else { | |
tabBar.frame = endFrame | |
return | |
} | |
// Perform animation with coordinato if one is given. Update safe area insets _after_ the animation is complete, | |
// if we're showing the tab bar. | |
weak var tabBarRef = self.tabBar | |
if let tc = transitionCoordinator { | |
tc.animateAlongsideTransition(in: self.view, animation: { _ in tabBarRef?.frame = endFrame }) { context in | |
if !hidden, let insets = context.isCancelled ? originalInsets : newInsets { | |
set(childViewController: vc, additionalSafeArea: insets) | |
} | |
} | |
} else { | |
UIView.animate(withDuration: 0.3, animations: { tabBarRef?.frame = endFrame }) { didFinish in | |
if !hidden, didFinish, let insets = newInsets { | |
set(childViewController: vc, additionalSafeArea: insets) | |
} | |
} | |
} | |
} | |
/// `true` if the tab bar is currently hidden. | |
var isTabBarHidden: Bool { | |
return !tabBar.frame.intersects(view.frame) | |
} | |
} |
extension UITabBarController {
func setTabBar(
hidden: Bool
) {
guard isTabBarHidden != hidden else { return }
let offsetY = hidden ? tabBar.frame.height : -tabBar.frame.height
let endFrame = tabBar.frame.offsetBy(dx: 0, dy: offsetY)
let cvc: UIViewController? = viewControllers?[selectedIndex]
var newInsets: UIEdgeInsets?
if #available(iOS 11.0, *) {
newInsets = cvc?.additionalSafeAreaInsets
}
weak var tabBarRef = self.tabBar
UIView.animate(withDuration: 0.1, animations: {
}, completion: { isFinished in
var height: CGFloat = 0
if #available(iOS 11.0, *) {
height = self.hasBottomNotch ? offsetY + (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0.0) : offsetY
} else {
height = offsetY
}
newInsets?.bottom -= height
if #available(iOS 11.0, *) {
cvc?.additionalSafeAreaInsets = newInsets!
} else {
cvc?.view.frame = CGRect(x: 0, y: 0,
width: cvc?.view.frame.width ?? 0.00,
height: (cvc?.view.frame.height ?? 0.00) + height)
}
if isFinished {
UIView.animate(withDuration: 0.2, animations: {
tabBarRef?.frame = endFrame
}, completion: nil)
}
})
}
var isTabBarHidden: Bool {
return !tabBar.frame.intersects(view.frame)
}
}
Refactored
Sweet! I'm not using this myself anymore, but maybe others have use for it :)
that only hide tabbar not tabbar item
I have recently used this extension. I found out one thing that after hiding the tabbar and then sending the app to background. Then again opening the app the tabbar reappears.
I found this leaves a blank space if the view controller in your tab bar is a UIHostingViewController.
Heres the fix:
extension UITabBarController {
/// Extends the size of the `UITabBarController` view frame, pushing the tab bar controller off screen.
/// - Parameters:
/// - hidden: Hide or Show the `UITabBar`
/// - animated: Animate the change
func setTabBarHidden(_ hidden: Bool, animated: Bool) {
guard let vc = selectedViewController else { return }
guard tabBarHidden != hidden else { return }
let frame = self.tabBar.frame
let height = frame.size.height
let offsetY = hidden ? height : -height
UIViewPropertyAnimator(duration: animated ? 0.3 : 0, curve: .easeOut) {
self.tabBar.frame = self.tabBar.frame.offsetBy(dx: 0, dy: offsetY)
self.selectedViewController?.view.frame = CGRect(
x: 0,
y: 0,
width: vc.view.frame.width,
height: vc.view.frame.height + offsetY
)
self.view.setNeedsDisplay()
self.view.layoutIfNeeded()
}
.startAnimation()
}
/// Is the tab bar currently off the screen.
private var tabBarHidden: Bool {
tabBar.frame.origin.y >= UIScreen.main.bounds.height
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This does not work properly on iPhone X...