iOS 在弹出视图控制器后不显示标签栏,hidesBottomBarWhenPush 设置为 true

iOS doesn't show tab bar after popping a view controller with hidesBottomBarWhenPushed sets to true

提问人:Saren Inden 提问时间:10/3/2023 更新时间:10/5/2023 访问量:21

问:

我对 .hidesBottomBarWhenPushed

它在按下(隐藏标签栏)和弹出(显示标签栏)时正常工作。但我有这个小宝石:

  • 有一个 UITabBarController,它有一个 UINavigationController 作为选项卡,其中包含一个 UIViewController
  • 在堆栈上推送一个新的 UIViewController,此视图控制器已在 init 中设置为 true。标签栏已正确隐藏hidesBottomBarWhenPushed
  • 此视图中有一个按钮,用于执行两个操作
    • 以模式呈现新的视图控制器(全屏,用于工作表演示,这有效)
    • 弹出当前视图控制器
  • 关闭以模式呈现的视图
  • 初始 UINavigationController 与其子项一起显示,但选项卡栏仍处于隐藏状态

因此,可悲的是,由于没有官方函数可以调用UITabBarController来隐藏或显示UITabBar,因此我没有看到解决此问题的好方法。也没有重新评估当前状态的功能。

如果演示稍有延迟,一切正常(但有些利益相关者不希望这样......

因此,这是重现该错误的完整代码(假设一个新项目具有情节提要,其中有一个 UITabBarController 作为入口点,其中有一个 UINavigationController,其中 作为其子项)ViewController

请原谅“丑陋”,它只是简单的演示代码

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tabBarController?.tabBar.isTranslucent = false
        
        view.backgroundColor = .red
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.navigationController?.pushViewController(VC2(), animated: true)
        }
    }
}


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 nvc = self.navigationController
            let vc = UINavigationController(rootViewController: VC3())
            vc.modalPresentationStyle = .fullScreen
            
            // With a delay it all works fine
//            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                nvc?.present(vc, animated: true)
//            }

            self.navigationController?.popViewController(animated: true)
        }), menu: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .blue
    }
}

class VC3: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .green
        
        navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction(handler: { _ in
            self.dismiss(animated: true)
        }))
    }
}
iOS UIKit UInageController: UITabbarController

评论


答:

0赞 Saren Inden 10/5/2023 #1

似乎一个“hacky”解决方案是对“拥有”UINavigationController进行修改

override public func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Determine if we are in the invalid state
    guard
        let tabBarController,
        tabBarController.tabBar.isHidden,
        let last = children.last,
        !last.hidesBottomBarWhenPushed
    else {
        return
    }

    // Force the navigation controller to reevaluate the current `hidesBottomBarWhenPushed`
    pushViewController(UIViewController(), animated: false)
    popViewController(animated: false)

    // The safe space is shown but the tab bar is still set to hidden
    tabBarController.tabBar.isHidden = false
}

对我来说,这在没有任何视觉伪影的情况下工作,但它也有点骇人听闻,这总是一个有问题的解决方案。

0赞 Saren Inden 10/5/2023 #2

我找到了另一种解决方案。仅当订单类似于

vc.present(modalVC, animated: true)
...
self.navigationController?.popViewController(animated: false)

而不是相反(所以现在必须在流行音乐之前完成)

var animatedPop = true

if let presentedViewController, presentedViewController.modalPresentationStyle == .fullScreen {
    animatedPop = false
}

navigationController?.popViewController(animated: animatedPop)

显然,出于某种神奇的原因,系统确实正确评估了hidesBottomBarWhenPushed