我一直在寻找如何过渡/动画barTintColor
UINavigationBar
一段时间,我只看到不同的答案。有些使用UIView.animateWithDuration
,有些使用CATransition
,但最有趣的是this one使用animate(alongsideTransition animation..
,我喜欢它的声音,但我无法获得它工作正常。我做错了吗?
许多人指定我可以简单地使用transitionCoordinator
中的viewWillAppear:
。我已经建立了一个像这样的新超级小项目:
class RootViewController:UIViewController{ //Only subclassed
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setNavigationColors(){
//Override in subclasses
}
}
class FirstViewController: RootViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "First"
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.tintColor = UIColor.black
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.black]
navigationController?.navigationBar.barStyle = UIBarStyle.default
}
}
class SecondViewController: RootViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Second"
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.black
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.navigationBar.barStyle = UIBarStyle.black
}
}
First
到Second
的推送过渡看起来很完美。所有元素都完美过渡,可能除了StatusBar,它立即变为白色。我宁愿知道如何转换它,但我现在就接受它。Second
到First
的流行转换是完全错误的。它保持Second
的颜色,直到转换完成。Second
到First
的拖动过渡看起来没问题,一直拖动。同样,一旦我开始拖动,StatusBar立即变黑,但我不知道是否可以修复。Second
到First
的拖动转换,但取消了拖动中途并返回Second
完全搞砸了。它看起来很好,直到Second
完全恢复控制,然后它突然变为First
- 颜色。这不应该发生。我对RootViewController
进行了一些更改,以使其更好一些。我完全删除了viewWillAppear:
,并将其更改为:
class RootViewController:UIViewController{
override func willMove(toParentViewController parent: UIViewController?) {
if let last = self.navigationController?.viewControllers.last as? RootViewController{
if last == self && self.navigationController!.viewControllers.count > 1{
if let parent = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - 2] as? RootViewController{
parent.setNavigationColors()
}
}
}
}
override func viewWillDisappear(_ animated: Bool) {
if let parent = navigationController?.viewControllers.last as? RootViewController{
parent.animateNavigationColors()
}
}
override func viewDidAppear(_ animated: Bool) {
self.setNavigationColors()
}
func animateNavigationColors(){
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setNavigationColors(){
//Override in subclasses
}
}
一些观察结果:
First
到Second
的转换是相同的Second
到First
的弹出式转换现在正确动画,除了后箭头,后退文本(和statusBar,但是是啊......)。这些立即变为黑色。在第一个gif中,您可以看到后箭头和后退文本也已转换。Second
到First
的拖动过渡也存在此问题,启动时后箭头和后退文本突然立即变黑。 barTint是固定的,因此在取消阻力时它不会出现错误的颜色。我做错了什么?我该怎么做?
我想要的是顺利过渡所有元素。后退按钮,后退文本,标题,barTint和statusBar的色调。这不可能吗?
答案 0 :(得分:6)
在10个iOS中它运作不完美:(
将导航控制器子类化为使用可见视图控制器的statusbarstyle:
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return visibleViewController!.preferredStatusBarStyle
}
}
覆盖Root控制器中的preferredStatusBarStyle并添加函数以在 pop动画之前设置样式:
private var _preferredStyle = UIStatusBarStyle.default;
override var preferredStatusBarStyle: UIStatusBarStyle {
get {
return _preferredStyle
}
set {
_preferredStyle = newValue
self.setNeedsStatusBarAppearanceUpdate()
}
}
func animateNavigationColors(){
self.setBeforePopNavigationColors()
transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
self?.setNavigationColors()
}, completion: nil)
}
func setBeforePopNavigationColors() {
//Override in subclasses
}
在第一个控制器中:
override func setBeforePopNavigationColors() {
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.white
navigationController?.navigationBar.tintColor = UIColor.black
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
navigationController?.navigationBar.barStyle = UIBarStyle.default
self.preferredStatusBarStyle = UIStatusBarStyle.default
}
第二名:
override func setNavigationColors(){
navigationController?.navigationBar.barTintColor = UIColor.black
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
navigationController?.navigationBar.barStyle = UIBarStyle.black
self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}
答案 1 :(得分:2)
您可以覆盖UINavigationController
的推送和弹出方法来设置条形颜色。我在其导航项中存储了与视图控制器对应的条形颜色,其自定义子类为UINavigationItem
。以下代码适用于iOS 11中的完整和交互式转换:
import UIKit
class NavigationItem: UINavigationItem {
@IBInspectable public var barTintColor: UIColor?
}
class NavigationController: UINavigationController, UIGestureRecognizerDelegate {
func applyTint(_ navigationItem: UINavigationItem?) {
if let item = navigationItem as? NavigationItem {
self.navigationBar.barTintColor = item.barTintColor
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
applyTint(self.topViewController?.navigationItem)
self.interactivePopGestureRecognizer?.delegate = self
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
applyTint(viewController.navigationItem)
super.pushViewController(viewController, animated: animated)
}
override func popViewController(animated: Bool) -> UIViewController? {
let viewController = super.popViewController(animated: animated)
applyTint(self.topViewController?.navigationItem)
return viewController
}
override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
let result = super.popToViewController(viewController, animated: animated)
applyTint(viewController.navigationItem)
return result
}
override func popToRootViewController(animated: Bool) -> [UIViewController]? {
let result = super.popToRootViewController(animated: animated)
applyTint(self.topViewController?.navigationItem)
return result
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return (otherGestureRecognizer is UIScreenEdgePanGestureRecognizer)
}
}
注意:颜色动画的协调由导航控制器
完成