web-dev-qa-db-ja.com

UINavigationBarの色を遷移/アニメーションするにはどうすればよいですか?

barTintColorUINavigationBarを移行/アニメーション化する方法をしばらく探していましたが、答えが異なるだけです。一部は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

  • 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
    }
}

この更新されたコードで、私はこれを取得します: Second

いくつかの観察:

  • FirstからSecondへの遷移は同じです
  • SecondからFirstへのpop遷移が正しく戻るようになりました。ただし、戻る矢印、戻るテキスト(およびstatusBarですが、そうです)を除きます。これらはすぐに黒に変わります。最初のgifでは、戻る矢印と戻るテキストも遷移したことがわかります。
  • SecondからFirstへのドラッグ遷移にもこの問題があり、開始時に戻る矢印と戻るテキストが突然一瞬で黒くなる。ドラッグをキャンセルしたときに間違った色にならないようにbarTintが修正されました。

何が悪いのですか?どうすればよいですか?

すべての要素をスムーズに移行したいです。戻るボタンの色合い、背景テキスト、タイトル、barTint、およびstatusBar。これは不可能ですか?

30
Sti

enter image description here

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

7
Josshad

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)
    }
}

注:カラーアニメーションの調整は、ナビゲーションコントローラーによって行われます。

2
clemens