UINavigationBar滑开,而不是留在原地

我创build了演示项目来显示问题。

我们在UINavigationController里有两个视图控制器。

MainViewController是根。

 class MainViewController: UIViewController { lazy var button: UIButton = { let button = UIButton() button.setTitle("Detail", for: .normal) return button }() override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Main" view.backgroundColor = .blue view.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true button.widthAnchor.constraint(equalToConstant: 150).isActive = true button.heightAnchor.constraint(equalToConstant: 42).isActive = true button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) } @objc func buttonTapped(_ sender: UIButton) { navigationController?.pushViewController(DetailViewController(), animated: true) } } 

和被推送的DetailViewController

 class DetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated: animated) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.setNavigationBarHidden(false, animated: animated) } } 

正如你所看到的,我想隐藏DetailViewController UINavigationBar

演示

问题是,UINavigationBar滑动而不是与整个MainViewController一起留在他的位置。 我怎样才能改变这种行为,并保持stream行手势?

在你的MainViewController添加该方法

 override func viewDidAppear(_ animated: Bool) { UIView.animate(withDuration: 0) { self.navigationController?.setNavigationBarHidden(false, animated: false) } } 

DetailViewController中用下面的方法replace你的方法

  override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.setNavigationBarHidden(true, animated: animated) } 

下面的代码是黑客。

 override func viewDidAppear(_ animated: Bool) { UIView.animate(withDuration: 0) { self.navigationController?.setNavigationBarHidden(false, animated: false) } } 

不要像@sagarbhut在他的post (在这个post中)所build议的那样写这个奇怪的代码。

你有两个select。

  1. 不要破解。

使用像这样的便利function

https://developer.apple.com/documentation/uikit/uiview/1622562-transition

如果您正在使用故事板,请创build一个自定义search。

https://www.appcoda.com/custom-segue-animations/

实现UIViewControllerAnimatedTransitioning协议

https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning

你可以得到一些很好的结果,但是恐怕你需要努力工作。 网上有很多教程讨论如何实现上述。

在这里输入图像说明

Twitter的导航转换,其中推动的ViewController的视图似乎采取整个屏幕“隐藏导航 ,但即使在过渡animation,即使在推动ViewController中仍然有popup手势animation和导航条可见,显然不能通过设置酒吧的隐藏属性。

实现自定义导航系统是一种方法,但我build议通过在navigationBar的图层和它的zPosition属性上玩一个简单的解决scheme。 你需要两个步骤,

  • 将navigationBar的图层zPosition设置为一个值,该值将其置于其包含导航堆栈中当前可见视图控制器视图的同胞之下: navigationController?.navigationBar.layer.zPosition = -1

    推动VC的viewDidLoad可能是一个很好的地方。

  • 既然navigationBar被放置在VC视图的后面,您需要调整视图的框架以确保它不与导航条重叠(导致导航条被覆盖)。 您可以使用viewWillLayoutSubviews更改视图的origin.y,以在navigationBar的底部(statusBarHeight + navigationBarHeight)下启动。

那会做这个工作 你不需要修改推送的VC,除非你想添加一个自定义的后退button,如在Twitter的个人资料屏幕的情况下。 细节控制器的视图将在导航栏的顶部,同时让您保持stream行的手势转换。 以下是您的示例代码修改此更改:

 class MainViewController: UIViewController { lazy var button: UIButton = { let button = UIButton() button.setTitle("Detail", for: .normal) button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Main" view.backgroundColor = .blue // Default value of layer's zPosition is 0 so setting it to -1 will place it behind its siblings. navigationController?.navigationBar.layer.zPosition = -1 // The `view` will be under navigationBar so lets set a background color to the bar // as the view's backgroundColor to simulate the default behaviour. navigationController?.navigationBar.backgroundColor = view.backgroundColor // Hide the back button transition image. navigationController?.navigationBar.backIndicatorImage = UIImage() navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage() view.addSubview(button) addConstraints() } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // Place `view` under navigationBar. let statusBarPlusNavigationBarHeight: CGFloat = (navigationController?.navigationBar.bounds.height ?? 0) + UIApplication.shared.statusBarFrame.height let viewHeight = UIScreen.main.bounds.height - statusBarPlusNavigationBarHeight view.frame = CGRect(origin: .zero, size: CGSize(width: view.bounds.width, height: viewHeight)) view.frame.origin.y = statusBarPlusNavigationBarHeight } @objc func buttonTapped(_ sender: UIButton) { navigationController?.pushViewController(DetailViewController(), animated: true) } private func addConstraints() { button.translatesAutoresizingMaskIntoConstraints = false button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true button.widthAnchor.constraint(equalToConstant: 150).isActive = true button.heightAnchor.constraint(equalToConstant: 42).isActive = true } } class DetailViewController: UIViewController { // Some giant button to replace the navigationBar's back button item :) lazy var button: UIButton = { let b: UIButton = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: 80, height: 40))) b.frame.origin.y = UIApplication.shared.statusBarFrame.height b.backgroundColor = .darkGray b.setTitle("back", for: .normal) b.addTarget(self, action: #selector(DetailViewController.backButtonTapped), for: .touchUpInside) return b }() @objc func backButtonTapped() { navigationController?.popViewController(animated: true) } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white view.addSubview(button) } } 

可能是你要找的…

开始推送/popup之前启动导航栏隐藏/显示animation:

 class MainViewController: UIViewController { lazy var button: UIButton = { let button = UIButton() button.setTitle("Detail", for: .normal) return button }() override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Main" view.backgroundColor = .blue view.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true button.widthAnchor.constraint(equalToConstant: 150).isActive = true button.heightAnchor.constraint(equalToConstant: 42).isActive = true button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) } @objc func buttonTapped(_ sender: UIButton) { navigationController?.setNavigationBarHidden(true, animated: true) navigationController?.pushViewController(DetailViewController(), animated: true) } } class DetailViewController: UIViewController { lazy var button: UIButton = { let button = UIButton() button.setTitle("Go Back", for: .normal) button.backgroundColor = .red return button }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white view.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true button.widthAnchor.constraint(equalToConstant: 150).isActive = true button.heightAnchor.constraint(equalToConstant: 42).isActive = true button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) } @objc func buttonTapped(_ sender: UIButton) { navigationController?.setNavigationBarHidden(false, animated: true) navigationController?.popViewController(animated: true) } } 

使用自定义推送转换从这个poststackoverflow.com/a/5660278/7270113。 为了消除背部的手势(这就是我所理解的是你想要做的),只要杀死导航堆栈。 您将不得不提供另一种方式来退出DetailViewController ,因为即使取消隐藏导航控制器,由于导航堆栈是空的,后退将消失。

 @objc func buttonTapped(_ sender: UIButton) { let transition = CATransition() transition.duration = 0.5 transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) transition.type = kCATransitionFade navigationController?.view.layer.add(transition, forKey: nil) let storyboard = UIStoryboard(name: "NameOfYourStoryBoard", bundle: .main) let viewController = storyboard.instantiateViewController(withIdentifier: "IdentifierOfDetailViewController") as! DetailViewController navigationController?.setViewControllers([viewController], animated: true) // This method will perform a push } 

您的导航控制器将从现在开始使用这个过渡animation,如果你想删除它可以使用

 navigationController?.view.layer.removeAllAnimations()