Ios UINavigationBar滑开,而不是停留在原地
我创建了一个演示项目来展示这个问题 我们在UINavigationController中有两个视图控制器Ios UINavigationBar滑开,而不是停留在原地,ios,swift,uinavigationcontroller,uinavigationbar,Ios,Swift,Uinavigationcontroller,Uinavigationbar,我创建了一个演示项目来展示这个问题 我们在UINavigationController中有两个视图控制器 MainViewController它是根目录 class MainViewController: UIViewController { lazy var button: UIButton = { let button = UIButton() button.setTitle("Detail", for: .normal) retur
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呆在一起。如何更改该行为并保持弹出手势?使用此post stackoverflow.com/a/5660278/7270113中的自定义推送转换。为了消除背部姿势(我理解这是您想要做的),只需关闭导航堆栈。您必须提供另一种退出
DetailViewController
的方法,因为即使您取消隐藏导航控制器,由于导航堆栈为空,Backfitten也将消失
@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()
这可能就是你要找的
在开始推/弹出之前,启动导航栏隐藏/显示动画:
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)
}
}
在
MainViewController
中添加该方法
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 0) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
}
并在DetailViewController
下面的代码是黑客攻击
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 0) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
}
不要像@sagarbhut在(本线程中)中建议的那样编写这种奇怪的代码
你有两个选择
推特的导航转换,推送的ViewController视图似乎占据了整个屏幕“隐藏导航栏”,但是,即使在过渡动画期间,仍然可以在推送ViewController中看到pop手势动画和导航栏,这显然无法通过设置栏的隐藏属性来实现 实现自定义导航系统是实现这一点的一种方法,但我建议使用navigationBar的层及其zPosition属性来实现一个简单的解决方案。你需要两个步骤
- 将navigationBar的layer zPosition设置为一个值,该值将放置在其同级项下,同级项包括导航堆栈中当前可见视图控制器的视图:
推动VC的viewDidLoad可能是一个很好的地方navigationController?.navigationBar.layer.zPosition=-1
- 既然navigationBar被放置在VC的视图后面,那么您需要调整视图的框架以确保它不会与navigationBar重叠(这会导致navigationBar被覆盖)。您可以使用viewWillLayoutSubviews更改视图的原点.y,以在navigationBar的楼层下开始(statusBarHeight+navigationBarHeight)
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)
}
}
它是一个导航控制器堆栈,由
navigationController
管理。它与问题有何关系?这些信息将如何帮助我更改UINavigationBar的行为,它会滑走,而不是停留在MainViewController的位置上?是否希望在视图转换期间使NAVIGATIONBAR动画化?您可以尝试将其隐藏在viewdide
中。。。这应该会给你动画效果,但它会在新视图滑动到位后出现。确切地说,它会一直保持到DetailViewController的动画结束,这很可怕。导航栏应该与下面的内容保持一致,我不知道为什么苹果开发者会将其更改为内容之外的幻灯片…@ThirdMartian我认为你应该创建一个自定义演示文稿。不,我认为是一样的!不是,像我写的那样尝试一下,你会得到你想要的东西不同类型的实例化视图控制器会有帮助吗?我说过几次,我想保持弹出手势。您的代码没有禁用它,但当您使用手势弹出时,导航栏会从左侧滑动,这不是我想要实现的。结果是UINavigationBar滑到顶部,并且在DetailViewController上可见一毫秒。看起来不太好。点击user.OK时查看Twitter应用程序-我会尝试查看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'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)
}
}