iOS设置hidesBottomBarWhenPushed后Pop页面TabBar不显示问题
解决
hidesBottomBarWhenPushed引发的TabBar异常隐藏问题 问题复现场景
- UITabBarController的标签页为嵌套单个UIViewController的UINavigationController;
- Push初始化时设置
hidesBottomBarWhenPushed = true的VC2,TabBar正常隐藏; - VC2内按钮同时执行两个操作:全屏present VC3、pop当前VC2;
- dismiss VC3回到初始页面后,TabBar仍保持隐藏状态,延迟present可修复但不符合需求。
问题根源
同一Runloop内同时执行pop和present操作,打乱了UITabBarController的状态评估逻辑,导致它未能正确识别当前栈顶控制器已无需隐藏TabBar。
解决方案
无需延迟present,只需确保present操作在pop动画完成后执行,让UITabBarController有足够时间更新状态。以下提供两种可行方案:
方案一:利用CATransaction监听pop动画完成
修改VC2的按钮点击事件,通过CATransaction的完成回调在pop结束后触发present:
class VC2: UIViewController { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) hidesBottomBarWhenPushed = true navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction(handler: { _ in let vc = UINavigationController(rootViewController: VC3()) vc.modalPresentationStyle = .fullScreen // 监听pop动画完成后执行present CATransaction.begin() CATransaction.setCompletionBlock { self.navigationController?.present(vc, animated: true) } self.navigationController?.popViewController(animated: true) CATransaction.commit() }), menu: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .blue } }
方案二:通过UINavigationControllerDelegate回调处理
让VC2遵守导航控制器代理协议,在pop完成后的回调中执行present:
class VC2: UIViewController, UINavigationControllerDelegate { private var pendingPresentVC: UIViewController? override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) hidesBottomBarWhenPushed = true navigationController?.delegate = self navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction(handler: { _ in let vc = UINavigationController(rootViewController: VC3()) vc.modalPresentationStyle = .fullScreen self.pendingPresentVC = vc self.navigationController?.popViewController(animated: true) }), menu: nil) } func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { guard let pendingVC = pendingPresentVC else { return } navigationController.present(pendingVC, animated: true) pendingPresentVC = nil } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .blue } }
两种方案均无需延迟操作,能确保dismiss VC3后TabBar正常显示,因为present操作会在pop动画完全结束后执行,UITabBarController有足够时间重新评估TabBar的显示状态。
内容的提问来源于stack exchange,提问作者Saren Inden
相关产品推荐
相关产品推荐

