[iOS 18] UITabBarController disable new switching animation

Hello !

Since iOS/iPadOS 18 there is a new switch transition between tabs in UITabBarController where is a little zoom of the selected UIViewController.

At first, I thought that was a bug but I found the same animation on the Apple's apps (like music, shortcuts...)

On my app, this animation produce a little flash/blink white before zooming, it's not smooth like on Apple's apps.

I searched on documentation but I didn't found any topics about how to disable it or handled it better.

Is this possible to disabled it ?

Answered by DTS Engineer in 802390022

You might be able to disable or provide a custom transition using tabBarController(_:animationControllerForTransitionFrom:to:)

Without a test project, it's hard to verify. You could give that a try on your end or you could please share a link to your test project. If you're not familiar with preparing a test project, take a look at Creating a test project

Could you post code for a minimum app so that we can test the effect ?

Accepted Answer

You might be able to disable or provide a custom transition using tabBarController(_:animationControllerForTransitionFrom:to:)

Without a test project, it's hard to verify. You could give that a try on your end or you could please share a link to your test project. If you're not familiar with preparing a test project, take a look at Creating a test project

tabBarController(_:animationControllerForTransitionFrom:to:) with returning nil doesn't work.

I had to create a custom fade transition with instant time duration.

Thanks for help :)

final class TabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()
    
        if #available(iOS 18.0, *) {
            delegate = self
        }
    }
}

extension TabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController,
                      to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }
}

extension TabBarController: UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: (any UIViewControllerContextTransitioning)?) -> TimeInterval {
        return .zero
    }

    func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) {
        guard let view = transitionContext.view(forKey: .to)
            else {
                return
        }
    
        let container = transitionContext.containerView
        container.addSubview(view)

        transitionContext.completeTransition(true)
    }
}

I tried the solution from and observed that on some changes of the tab the background of my tabbar vanished, letting me fully see underneath content for a split second and then restored to it's previous state. Also I had issues with NavigationControllers where the NavigationBar is hidden on some of the ViewControllers. Hiding and unhiding them in view lifecycle methods become visible and animated although the transitionDuration (code from ) was .zero.

So I came up with something else.

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
	if let targetIndex = tabBarController.viewControllers?.firstIndex(where: { $0 == viewController }) {
		UIView.performWithoutAnimation {
			tabBarController.selectedIndex = targetIndex
		}
	}
	return false
}

Basically I'm intercepting normal tab changes by pressing on them and then programmatically perform them instead and suppress the animations. Just that works great and I couldn't find any issues with it, yet.

#import "TabBarVC.h"

@interface TabBarVC () <UIViewControllerAnimatedTransitioning, UITabBarControllerDelegate>

@end

@implementation TabBarVC

  • (void)viewDidLoad { [super viewDidLoad];

    self.delegate = self;

}

#pragma mark - UITabBarControllerDelegate

  • (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {

    return self;

}

#pragma mark - UIViewControllerAnimatedTransitioning

  • (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext { UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey]; [transitionContext.containerView addSubview:toView]; [transitionContext completeTransition:YES];

}

  • (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext { return 0;

}

@end

[iOS 18] UITabBarController disable new switching animation
 
 
Q