如何转换/动画UINavigationBar的颜色?
我一直在寻找如何过渡/动画UINavigationBar
的barTintColor
一段时间,我只看到不同的答案。 有些使用UIView.animateWithDuration
,有些使用CATransition
,但最有趣的是,像这个使用animate(alongsideTransition animation..
,我喜欢它的声音,但我不能让它正常工作。我做错了什么?
许多人指定我可以在viewWillAppear:
简单地使用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
-colors。 这不应该发生。
我对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的色调。 这不可能吗?
在10 iOS中它的工作不完美:(
将导航控制器子类化为使用可见视图控制器的statusbarstyle:
class MyNavigationController: UINavigationController { override var preferredStatusBarStyle: UIStatusBarStyle { return visibleViewController!.preferredStatusBarStyle } }
覆盖Root控制器中的preferredStatusBarStyle并添加函数以在弹出动画之前设置样式:
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 }
示例项目: https : //github.com/josshad/TestNavBarTransition
您可以覆盖UINavigationController
的push和pop方法来设置条形颜色。 我在其导航项中存储了与视图控制器对应的条形颜色,其中包含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) } }
注意:颜色动画的协调由导航控制器完成
- iOS中的Google日历应用urlscheme
- 在本地HTML文件加载图像 – UIWebView
- 错误使用未parsing的标识符GMSPlacePickerConfig&GooglePlacePicker? (Google Places 2.0)
- 什么时候可以使用带有通用链接的SFSafariViewController,WKWebView或UIWebView?
- 使用CAEmitterLayer在圆或CGPath周围绘制粒子
- 处理iPad迷你屏幕尺寸
- 在UITableView,最好的方法来取消已经离开屏幕的单元格的GCD操作?
- React-native run-ios命令失败
- UIImageView旋转图像与视网膜4 iPhone模拟器,而不是视网膜3.5 /常规模拟器