barTintColor
のUINavigationBar
を移行/アニメーション化する方法をしばらく探していましたが、答えが異なるだけです。一部はUIView.animateWithDuration
を使用し、一部はCATransition
を使用しますが、 this one のような最も興味深いものはanimate(alongsideTransition animation..
を使用します。正しく機能しない。私は何か間違ったことをしていますか?
多くの人は、viewWillAppear:
でtransitionCoordinator
を単純に使用できると指定しています。私はこのような新鮮な超小型プロジェクトをセットアップしました:
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
へのpop遷移が正しく戻るようになりました。ただし、戻る矢印、戻るテキスト(およびstatusBarですが、そうです)を除きます。これらはすぐに黒に変わります。最初のgifでは、戻る矢印と戻るテキストも遷移したことがわかります。Second
からFirst
へのドラッグ遷移にもこの問題があり、開始時に戻る矢印と戻るテキストが突然一瞬で黒くなる。ドラッグをキャンセルしたときに間違った色にならないようにbarTintが修正されました。何が悪いのですか?どうすればよいですか?
すべての要素をスムーズに移行したいです。戻るボタンの色合い、背景テキスト、タイトル、barTint、およびstatusBar。これは不可能ですか?
10 iOSではそれは不完全に機能します:(
ナビゲーションコントローラーをサブクラス化して、表示可能なビューコントローラーのステータスバースタイルを使用します。
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return visibleViewController!.preferredStatusBarStyle
}
}
ルートコントローラーのpreferredStatusBarStyleをオーバーライドし、スタイルを設定する関数を追加しますbeforepopアニメーション:
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)
}
}
注:カラーアニメーションの調整は、ナビゲーションコントローラーによって行われます。