UINavigationBar bounces instead of staying in place

I created a demo project to show the problem.

We have two view controllers in the UINavigationController.

MainViewControllerwhich is the root.

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)
    }
}

And DetailViewControllerthat is pressed.

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)
    }
}

As you can see, I want to hide UINavigationBarin DetailViewController:

Demo

Question

The problem is that the UINavigationBar bounces, instead of staying in place with the entire MainViewController. How can I change this behavior and maintain posture?

+4
source share
5 answers

in MainViewControlleradd this method

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

and replace the method below with DetailViewController

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

The following hack code.

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

, @sagarbhut ( ).

.

  • Hack

  • .

,

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

, .

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

UIViewControllerAnimatedTransitioning

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

, , . , , .

enter image description here

0

Twitter, , , ViewController " ", , ViewController , , .

- , , navigationBar zPosition. ,

  • navigationBar zPosition , , : navigationController?.navigationBar.layer.zPosition = -1

    VC viewDidLoad .

  • , VC, , , ( , navigationBar ). viewWillLayoutSubviews, origin.y, ( BarHeight + navigationBarHeight).

. VC, , , , Twitter. , -. , :

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 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 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 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)
    }
}
0

, ...

/ NavBar push/pop:

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)
    }

}
-1

push stackoverflow.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
}

, ,

navigationController?.view.layer.removeAllAnimations()
-2

Source: https://habr.com/ru/post/1689061/


All Articles