在推送时制作一个透明的导航栏并在弹出时恢复它
Make a transparent navigation bar on push and restore it on pop
我正在尝试创造一种效果,即使它接近我想要的效果,但它有一些 UI 故障,我将解释。
比方说,我有我的主页导航控制器,我点击一个单元格来推送一个新的视图控制器。
在该视图控制器的 viewWillAppear(:)
上,我实现了以下内容:
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.backgroundColor = .clear
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.barTintColor = .clear
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
通过这样做,推送的视图控制器将使其 navigationBar
透明,并且仍然保持按钮可见(这是我想要的),但是在推送动画中,它在父控制器,因为它也隐藏了父控制器的 navigationBar
。
然后在推送的视图控制器上 viewWillDisappear(_:)
我实现了以下内容:
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white
通过这样做,我试图重置父级的 navigationBar
默认属性,但是这样做我在动画期间看到一个黑条,在它完成动画之前,这会导致错误 UI/UX.
我是不是做错了什么,或者有更好的方法吗?
谢谢。
所以在经过一些挖掘和来自@Paulo 的一些非常有用的提示之后,我设法按照我的意愿解决了这个问题。
这应该更容易实现,Apple 应该为开发人员提供简单的选项,而不是绕过一些 hack 来实现它,但无论如何。
我发现其中一个秘密是我在浏览视图控制器时滥用了 navigationBar.isTranslucent = true / false
。
为了做到这一点,我在 parentViewController
中设置了默认的 navigationBar
属性,该属性将使用透明 navigationBar
; 推送到视图控制器;我按照以下方式完成了它:
self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
在 pushedViewController
viewWillAppear(_:)
您需要执行以下操作:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard self.navigationController?.topViewController === self else { return }
self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self?.navigationController?.navigationBar.shadowImage = UIImage()
self?.navigationController?.navigationBar.backgroundColor = .clear
self?.navigationController?.navigationBar.barTintColor = .clear
}, completion: nil)
}
这里我设置了想要的 navigationBar
透明度,但是正如你注意到的,不需要使用 isTranslucent
属性,我注意到通过强制 UI 会在推送动画上显示一些闪烁和奇怪的布局。
然后在同一个视图控制器(推送)上,您需要实现您在 parentViewController
:
中实现的默认、期望的 navigationBar
属性
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
self?.navigationController?.navigationBar.shadowImage = nil
self?.navigationController?.navigationBar.backgroundColor = .white
self?.navigationController?.navigationBar.barTintColor = .white
}, completion: nil)
}
通过这样做,一切都应该按预期工作。
希望对以后的人有所帮助。
经过 DAYS 的思考,我想我已经找到了最好的(但远非完美的)解决方案。这样您就可以在发生转换时自定义导航栏,还可以处理中断的转换,例如当用户取消弹出时。
func yourCustomizationMethod(bar: UINavigationBar) {
// Modify the navigation bar
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard navigationController?.topViewController == self else {
return
}
// The coordinator is nil in some cases
if let coordinator = transitionCoordinator,
coordinator.animate(alongsideTransition: { context in
guard let bar = self.navigationController?.navigationBar else {
return
}
self.yourCustomizationMethod(bar: bar)
}, completion: nil) {
return
} else if let bar = navigationController?.navigationBar {
yourCustomizationMethod(bar: bar)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Customize only if user transition gets canceled to avoid multiple customizations.
guard transitionCoordinator?.isCancelled == true,
let bar = navigationController?.navigationBar else {
return
}
yourCustomizationMethod(bar: bar)
}
我正在尝试创造一种效果,即使它接近我想要的效果,但它有一些 UI 故障,我将解释。
比方说,我有我的主页导航控制器,我点击一个单元格来推送一个新的视图控制器。
在该视图控制器的 viewWillAppear(:)
上,我实现了以下内容:
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.backgroundColor = .clear
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.barTintColor = .clear
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
通过这样做,推送的视图控制器将使其 navigationBar
透明,并且仍然保持按钮可见(这是我想要的),但是在推送动画中,它在父控制器,因为它也隐藏了父控制器的 navigationBar
。
然后在推送的视图控制器上 viewWillDisappear(_:)
我实现了以下内容:
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white
通过这样做,我试图重置父级的 navigationBar
默认属性,但是这样做我在动画期间看到一个黑条,在它完成动画之前,这会导致错误 UI/UX.
我是不是做错了什么,或者有更好的方法吗?
谢谢。
所以在经过一些挖掘和来自@Paulo 的一些非常有用的提示之后,我设法按照我的意愿解决了这个问题。
这应该更容易实现,Apple 应该为开发人员提供简单的选项,而不是绕过一些 hack 来实现它,但无论如何。
我发现其中一个秘密是我在浏览视图控制器时滥用了 navigationBar.isTranslucent = true / false
。
为了做到这一点,我在 parentViewController
中设置了默认的 navigationBar
属性,该属性将使用透明 navigationBar
; 推送到视图控制器;我按照以下方式完成了它:
self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
在 pushedViewController
viewWillAppear(_:)
您需要执行以下操作:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard self.navigationController?.topViewController === self else { return }
self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self?.navigationController?.navigationBar.shadowImage = UIImage()
self?.navigationController?.navigationBar.backgroundColor = .clear
self?.navigationController?.navigationBar.barTintColor = .clear
}, completion: nil)
}
这里我设置了想要的 navigationBar
透明度,但是正如你注意到的,不需要使用 isTranslucent
属性,我注意到通过强制 UI 会在推送动画上显示一些闪烁和奇怪的布局。
然后在同一个视图控制器(推送)上,您需要实现您在 parentViewController
:
navigationBar
属性
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
self?.navigationController?.navigationBar.shadowImage = nil
self?.navigationController?.navigationBar.backgroundColor = .white
self?.navigationController?.navigationBar.barTintColor = .white
}, completion: nil)
}
通过这样做,一切都应该按预期工作。
希望对以后的人有所帮助。
经过 DAYS 的思考,我想我已经找到了最好的(但远非完美的)解决方案。这样您就可以在发生转换时自定义导航栏,还可以处理中断的转换,例如当用户取消弹出时。
func yourCustomizationMethod(bar: UINavigationBar) {
// Modify the navigation bar
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard navigationController?.topViewController == self else {
return
}
// The coordinator is nil in some cases
if let coordinator = transitionCoordinator,
coordinator.animate(alongsideTransition: { context in
guard let bar = self.navigationController?.navigationBar else {
return
}
self.yourCustomizationMethod(bar: bar)
}, completion: nil) {
return
} else if let bar = navigationController?.navigationBar {
yourCustomizationMethod(bar: bar)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Customize only if user transition gets canceled to avoid multiple customizations.
guard transitionCoordinator?.isCancelled == true,
let bar = navigationController?.navigationBar else {
return
}
yourCustomizationMethod(bar: bar)
}