iOS开发 -- iOS 14下popToRootViewControllerAnimated:YES 导致TabBar隐藏的问题

本文探讨了在iOS14中使用Xcode12遇到的UITabBar显示与隐藏问题,并提供了解决方案。当使用popToRootViewControllerAnimated方法时,UITabBar可能会被意外隐藏。

写在前面

文章中的问题会出现在Xcode 12 + iOS 14上, 经过测试,

  • Xcode 11 + iOS14,
  • Xcode 12 + <= iOS 13

不会出此类问题.

问题

我们处理UITabbar在push的时候的显示和隐藏, 之前因该是如下的操作:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (self.viewControllers.count > 0) {
        viewController.hidesBottomBarWhenPushed = YES;
    } else {
        viewController.hidesBottomBarWhenPushed = NO;
    }
    [super pushViewController:viewController animated:animated];
}

这个在iOS 14之前是没问题的, 但是升级到iOS 14, 发现我们在执行 popToRootViewControllerAnimated:YES的时候, UITabBar隐藏了.

尝试

网上有说, 不执行动画就不会出现这个问题, 经过尝试, 确实不会出现这个问题, 但是感觉生硬, 所以暂时不考虑此类解决方案.

之后, 又尝试了几种方案都不行.如手动显示Tabbar等, 发现会出现混乱.

曙光

A->B->C    A <= C

最后, 尝试在C中将B从viewControllers中移除掉,
执行 popToRootViewControllerAnimated:YES的时候, UITabBar显示了,

于是猜测viewController.hidesBottomBarWhenPushed在iOS 14中针对当前导航存在过度设置的问题(说法可能不够官方).

解决

于是乎, 做了如下操作, 解决了问题:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (self.viewControllers.count > 0) {
    	// 当前导航栏, 只有第一个viewController push的时候设置隐藏
        if (self.viewControllers.count == 1) {
            viewController.hidesBottomBarWhenPushed = YES;
        }
    } else {
        viewController.hidesBottomBarWhenPushed = NO;
    }
    [super pushViewController:viewController animated:animated];
}

如果大佬们知道其原理, 希望可能多多指导小弟, 谢谢了.

#import "TPNavigationController.h" #import "TPContainerViewController.h" #import "TPContainerNavigationController.h" #import "UIViewController+TPNavigationExtension.h" #import <TPFoundation/TPUIUtils.h> @implementation TPContainerNavigationController + (instancetype)wrapNavigationControllerWithViewController:(UIViewController *)viewController { return [[self alloc] initWithViewController:viewController]; } - (instancetype)initWithViewController:(UIViewController *)viewController { if (self = [super init]) { self.viewControllers = @[viewController]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; // 禁用包装的vc的返回手势 self.interactivePopGestureRecognizer.enabled = NO; } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { TPContainerViewController *fromContainer = (TPContainerViewController *)self.navigationController.topViewController; if (![self shouldKeepOrientationFromController:[fromContainer rootViewController] toController:viewController]) { [self ensureOrientationIsPortrait]; } // push一个包装后的控制器 TPContainerViewController *wrapViewController = [TPContainerViewController wrapViewController:viewController]; if (self.tpNavigationController.viewControllers.count >= 1) { if (@available(iOS 9.0, *)) { wrapViewController.hidesBottomBarWhenPushed = YES; viewController.hidesBottomBarWhenPushed = YES; } else { // for iOS 8, set tabbar hidden [[self tabBarController].tabBar setHidden:YES]; } } //使用Xcode12.0.1编译的App,在iOS14上运行时,当调用popToRootViewControllerAnimated:YES到vc栈中非相邻的vc时,会发现rootViewController的tabbar消失了,如果是popToRootViewControllerAnimated:NO则没问题 // 应该是官方的bug,先复写该方法解决 else { if (@available(iOS 14.0, *)) { viewController.hidesBottomBarWhenPushed = NO; } } [self.navigationController pushViewController:wrapViewController animated:animated]; } - (UIViewController *)popViewControllerAnimated:(BOOL)animated { NSInteger controllersCount = self.navigationController.viewControllers.count; if (controllersCount > 1) { TPContainerViewController *fromContainer = (TPContainerViewController *)self.navigationController.topViewController; TPContainerViewController *toContainer = self.navigationController.viewControllers[controllersCount - 2]; if (![self shouldKeepOrientationFromController:[fromContainer rootViewController] toController:[toContainer rootViewController]]) { [self ensureOrientationIsPortrait]; } } if (self.navigationController) { return [self.navigationController popViewControllerAnimated:animated]; } return [super popViewControllerAnimated:animated]; } - (NSArray<UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated { [self ensureOrientationIsPortrait]; return [self.navigationController popToRootViewControllerAnimated:animated]; } - (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated { [self ensureOrientationIsPortrait]; TPNavigationController *tpNavigationController = viewController.tpNavigationController; // pop到指定vc时应找到对应的tpContainerViewController NSInteger index = [tpNavigationController.tpChildViewControllers indexOfObject:viewController]; return [self.navigationController popToViewController:tpNavigationController.viewControllers[index] animated:animated]; } - (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion { [self ensureOrientationIsPortrait]; [self.navigationController presentViewController:viewControllerToPresent animated:flag completion:completion]; } - (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion { [self ensureOrientationIsPortrait]; [self.navigationController dismissViewControllerAnimated:flag completion:completion]; } - (void)setDelegate:(id<UINavigationControllerDelegate>)delegate { self.navigationController.delegate = delegate; } - (void)ensureOrientationIsPortrait { if (UIInterfaceOrientationIsPortrait([TPUIUtils getScreenOrientation])) { return; } if (@available(iOS 16.0, *)) { [self setNeedsUpdateOfSupportedInterfaceOrientations]; } [TPUIUtils changeScreenOrientationTo:UIInterfaceOrientationPortrait]; } - (BOOL)shouldKeepOrientationFromController:(UIViewController *)fromController toController:(UIViewController *)toController { SEL selector = @selector(controllersNeedToKeepOrientationWhenNavigating); if ([fromController respondsToSelector:selector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" NSArray *controllers = [fromController performSelector:selector]; #pragma clang diagnostic pop NSString *toControllerName = NSStringFromClass([toController class]); if ([controllers containsObject:toControllerName]) { return YES; } } return NO; } @end
最新发布
09-27
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值