I ran across this problem today and successfully managed to have the TabBar slide down instead of to the left. It's working on iOS 13 at least.
I use the animator for my transition to additionally animate the TabBar and counteract the default animation.
class CustomTransition: NSObject, UIViewControllerAnimatedTransitioning {
static let duration: TimeInterval = 0.5
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
Self.duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let from = transitionContext.viewController(forKey: .from)!
let to = transitionContext.viewController(forKey: .to)!
let animator = UIViewPropertyAnimator(duration: Self.duration, curve: .easeInOut)
// Configure animator for transition like normal.
// ...
// Now handle the TabBar.
if
to.hidesBottomBarWhenPushed,
!from.hidesBottomBarWhenPushed,
let tabBar = from.tabBarController?.tabBar
{
// TabBar is going away.
animator.addAnimations {
// Counteract default animation by animating x in opposite direction.
tabBar.center.x += tabBar.bounds.width
// Animate TabBar down.
tabBar.center.y += tabBar.bounds.height
// Or alternatively animate opacity.
// tabBar.alpha = 0
}
}
else if
!to.hidesBottomBarWhenPushed,
from.hidesBottomBarWhenPushed,
let tabBar = to.tabBarController?.tabBar
{
// TabBar is coming back.
// TabBar by default will be animated toward default position.
// Make sure it's already there on x so default animation does nothing for x.
tabBar.center.x = tabBar.bounds.width / 2
// Move y down, so default animation will move TabBar up to default position.
tabBar.center.y += tabBar.bounds.height
// Or alternatively animate opacity.
// tabBar.alpha = 0
// animator.addAnimations {
// tabBar.alpha = 1
//}
}
animator.startAnimation()
}
}
EDIT:
The above solution doesn't seem to be working in landscape orientation.
I settled on the following solution instead, but it's getting hackier.
Somehow you can only remove the default animation from the TabBar layer after you start your own animation, like somehow those are related.
I've tested this on a variety of devices in different orientations and it seems to be working consistently, at least on iOS 13.
// Start transition animation.
animator.startAnimation()
if let tabBar = pushedController.tabBarController?.tabBar {
// Remove default TabBar animation.
tabBar.layer.removeAllAnimations()
if pushedController == to {
// Move TabBar back to its place.
tabBar.center.x = tabBar.bounds.width / 2
// Now animate it out again.
animator.addAnimations {
tabBar.center.y += tabBar.bounds.height
}
} else {
// Move TabBar down out of view.
tabBar.center.y += tabBar.bounds.height
// Now animate it in.
animator.addAnimations {
tabBar.center.y -= tabBar.bounds.height
}
}
}