web-dev-qa-db-ja.com

UINavigationBarはプッシュ時に色を変更します

異なるビューのUINavigationBarで2つの異なるバーティントカラーを使用しています。私は両方のビューでその方法で色を変更していません:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.barTintColor = COLOR
}

戻るボタンをタップすると、色がスムーズに変更されません(最後の1秒間に点滅が表示されます)。

Visual bug

ただし、[戻る]ボタンをタップする代わりにビューをスワイプするだけで問題ありません。

No visual bug

両方の状況でスムーズに移行するにはどうすればよいですか?

23
Vasily

私は最も使いやすい最終的なソリューションをコーディングしました(独自のビューコントローラーで多くのオーバーライドを使用する必要はありません)。 iOS 10で完全に動作し、独自の目的で簡単に採用できます。

GitHub

あなたは GitHub Gist でクラスの完全なコードと詳細なガイドを確認できます。Stackoverflowは大量のコードを格納するためのものではありません。

使用法

ダウンロードSwiftファイル。動作させるには、ColorableNavigationControllerの代わりにUINavigationControllerを使用し、必要な子ビューコントローラをNavigationBarColorableプロトコルに採用してください。

例:

class ViewControllerA: UIViewController, NavigationBarColorable {
    public var navigationBarTintColor: UIColor? { return UIColor.blue }

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Push", style: .plain, target: self, action: #selector(self.showController))
    }

    func showController() {
        navigationController?.pushViewController(ViewControllerB(), animated: true)
    }
}

class ViewControllerB: UIViewController, NavigationBarColorable {
    public var navigationBarTintColor: UIColor? { return UIColor.red }
}

let navigationController = ColorableNavigationController(rootViewController: ViewControllerA())
14
Vasily

この種類のアニメーションを実現するには、UIViewControllerTransitionCoordinatorAppleドキュメント として使用する必要があります。

UIViewControllerTransitionCoordinatorプロトコルを採用するオブジェクトは、ビューコントローラーの遷移に関連付けられたアニメーションをサポートします。(...)

したがって、すべてのUIViewControllerは独自のtransitionControllerを持っています。これを取得するには、UIViewControllerClassを呼び出す必要があります。

self.transitionCoordinator()

ドキュメント から:

アクティブな遷移コーディネーターオブジェクトを返します。

したがって、必要な結果を得るには、viewController transitionCoordinatiorにanimateAlongsideTransitionメソッドを実装する必要があります。 backButtonをクリックしてスワイプして戻ると、アニメーションが機能します。

例:

navigation_bar_animation

最初のコントローラー:

_class ViewControllerA: UIViewController {

    override func loadView() {
        super.loadView()
        title = "A"
        view.backgroundColor = .white
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "NEXT", style: .plain, target: self, action: #selector(self.showController))
        setColors()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        animate()
    }

    func showController() {
        navigationController?.pushViewController(ViewControllerB(), animated: true)
    }

    private func animate() {
        guard let coordinator = self.transitionCoordinator else {
            return
        }

        coordinator.animate(alongsideTransition: {
            [weak self] context in
            self?.setColors()
        }, completion: nil)
    }

    private func setColors() {
        navigationController?.navigationBar.tintColor = .black
        navigationController?.navigationBar.barTintColor = .red
    }
}
_

2番目のコントローラー:

_class ViewControllerB : UIViewController {

    override func loadView() {
        super.loadView()
        title = "B"
        view.backgroundColor = .white
        setColors()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        animate()
    }

    override func willMove(toParentViewController parent: UIViewController?) { // tricky part in iOS 10
        navigationController?.navigationBar.barTintColor = .red //previous color
        super.willMove(toParentViewController: parent)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        navigationController?.navigationBar.barTintColor = .blue
    }

    private func animate() {
        guard let coordinator = self.transitionCoordinator else {
            return
        }
        coordinator.animate(alongsideTransition: {
            [weak self] context in
            self?.setColors()
        }, completion: nil)
    }

    private func setColors(){
        navigationController?.navigationBar.tintColor = .black
        navigationController?.navigationBar.barTintColor = .blue
    }

}
_

UPDATE iOS 10

IOS 10では、トリッキーな部分はsecond ViewControllerにwillMoveTo(parentViewController parent: UIViewController?)を追加することです。そして、navigationBar tintColorpreviousコントローラのカラー値に設定します。また、viewDidAppearメソッドのsecond ViewControlerは、_navigationBar.tintColor_をsecond viewController。

私の例をチェックしてください githubのプロジェクト

19
kamwysoc

これは私のために働きました:

 override func willMove(toParent parent: UIViewController?) {
      super.willMove(toParent: parent)
      navigationController?.navigationBar.barTintColor = previous view controller's navigation bar color
 }
2
sash

私はちょうど不思議です。同じ目的でUINavigationControllerDelegateを使用します。 navigationController(_:willShow:)では、transitionCoordinator?.animate(alongsideTransition:completion:)を使用してアニメーションを開始します。新しいコントローラーをプッシュするときはうまくいきますが、popはそうではありません。

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
  let dst = viewController as! ViewController
  guard animated else {
    navigationController.navigationBar.barTintColor = dst.navigationBarColor
    navigationController.navigationBar.tintColor = dst.tintColor
    navigationController.navigationBar.barStyle = dst.barStyle
    return
  }

  navigationController.transitionCoordinator?.animate(alongsideTransition: { context in
    navigationController.navigationBar.barTintColor = dst.navigationBarColor
    navigationController.navigationBar.tintColor = dst.tintColor
    navigationController.navigationBar.barStyle = dst.barStyle
  }, completion: { context in
    if context.isCancelled {
      let source = context.viewController(forKey: UITransitionContextViewControllerKey.from) as! ViewController
        navigationController.navigationBar.barTintColor = source.navigationBarColor
        navigationController.navigationBar.tintColor = source.tintColor
        navigationController.navigationBar.barStyle = source.barStyle
    }
})

それがプッシュでは機能するがポップでは機能しない理由はありますか?

Push and pop

1
olejnjak