XCode 8.0/iOS 10にアップグレードしましたが、ナビゲーションバーの色変更アニメーションが機能しなくなり、アニメーションなしで直接色が変更されます。
UIView.animateWithDuration(0.2, animations: {
self.navigationController?.navigationBar.barTintColor = currentSection.color!
})
誰もがこれを修正する方法を知っていますか?
IOS10でnavigationBarの色の変化をアニメーション化するには、アニメーションブロック内の色を設定した後、layoutIfNeeded
を呼び出す必要があります。
コード例:
UIView.animateWithDuration(0.5) {
self.navigationController?.navigationBar.barTintColor = UIColor.redColor()
self.navigationController?.navigationBar.layoutIfNeeded()
}
また、メソッドがいつでも壊れることがあるように、Apple 公式にはサポートされていません barTintColorなどのプロパティのアニメーションを通知したいと思います。
アニメーションブロック中にナビゲーションバーで-layoutIfNeededを呼び出すと、背景プロパティが更新されますが、これらのプロパティの機能の性質を考えると、これらのプロパティのいずれかをアニメーション化できるという保証はありません。
プロトコルを定義します。
/// Navigation bar colors for `ColorableNavigationController`, called on `Push` & `pop` actions
public protocol NavigationBarColorable: UIViewController {
var navigationTintColor: UIColor? { get }
var navigationBarTintColor: UIColor? { get }
}
public extension NavigationBarColorable {
var navigationTintColor: UIColor? { return nil }
}
カスタムNavigationController
サブクラスを定義します。
class AppNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.shadowImage = UIImage()
if let colors = rootViewController as? NavigationBarColorable {
setNavigationBarColors(colors)
}
}
private var previousViewController: UIViewController? {
guard viewControllers.count > 1 else {
return nil
}
return viewControllers[viewControllers.count - 2]
}
override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
if let colors = viewController as? NavigationBarColorable {
setNavigationBarColors(colors)
}
super.pushViewController(viewController, animated: animated)
}
override open func popViewController(animated: Bool) -> UIViewController? {
if let colors = previousViewController as? NavigationBarColorable {
setNavigationBarColors(colors)
}
// Let's start pop action or we can't get transitionCoordinator()
let popViewController = super.popViewController(animated: animated)
// Secure situation if user cancelled transition
transitionCoordinator?.animate(alongsideTransition: nil, completion: { [weak self] context in
guard let `self` = self else { return }
guard let colors = self.topViewController as? NavigationBarColorable else { return }
self.setNavigationBarColors(colors)
})
return popViewController
}
override func popToRootViewController(animated: Bool) -> [UIViewController]? {
if let colors = rootViewController as? NavigationBarColorable {
setNavigationBarColors(colors)
}
let controllers = super.popToRootViewController(animated: animated)
return controllers
}
private func setNavigationBarColors(_ colors: NavigationBarColorable) {
if let tintColor = colors.navigationTintColor {
navigationBar.titleTextAttributes = [
.foregroundColor : tintColor
]
navigationBar.tintColor = tintColor
}
navigationBar.barTintColor = colors.navigationBarTintColor
}
}
これで、NavigationBarColorable
内の任意のコントローラーのAppNavigationController
に準拠し、任意の色を指定できます。
extension FirstViewController: NavigationBarColorable {
public var navigationBarTintColor: UIColor? { UIColor.red }
public var navigationTintColor: UIColor? { UIColor.white }
}
extension SecondViewController: NavigationBarColorable {
public var navigationBarTintColor: UIColor? { UIColor.blue }
public var navigationTintColor: UIColor? { UIColor.orange }
}
この便利な拡張機能を実装することを忘れないでください:
extension UINavigationController {
var rootViewController: UIViewController? {
return viewControllers.first
}
}