preferredStatusBarStyleは呼び出されません


257

私は、その後、このスレッドをオーバーライドする-preferredStatusBarStyleが、それは呼び出されません。それを有効にするために変更できるオプションはありますか?(プロジェクトでXIBを使用しています。)


どのような状況で呼び出されません:シミュレータ?デバイス上で?
13

@bneely両方。
trgoofi 2013

iOS 7シミュレーター、iOS 7デバイスを使用しており、ベースSDKは7.0ですか?
わずか

@bneely iOS SDK 7.0がプロジェクト名の下に表示されていますが、これはベースSDKが7.0であることを意味しますか?
trgoofi 2013

ビルド設定では、「Base SDK」が値が設定される場所です。プロジェクトが7.0に設定されているようです。
13

回答:


117

考えられる根本的な原因

同じ問題があり、アプリケーションウィンドウでルートビューコントローラーを設定していなかったために発生していることがわかりました。

UIViewController実装したpreferredStatusBarStyleはで使用さUITabBarControllerれ、画面上のビューの外観を制御しました。

ルートビューコントローラーをthisを指すように設定するUITabBarControllerと、ステータスバーの変更が期待どおりに(およびpreferredStatusBarStyleメソッドが呼び出されて)正しく機能し始めました。

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ... // other view controller loading/setup code

    self.window.rootViewController = rootTabBarController;
    [self.window makeKeyAndVisible];
    return YES;
}

代替方法(iOS 9で非推奨)

または、を使用する代わりに、背景色に応じて、各View Controllerで次のメソッドのいずれかを適宜呼び出すことができますsetNeedsStatusBarAppearanceUpdate

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

または

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

この方法を使用する場合は、plistファイルにもを設定UIViewControllerBasedStatusBarAppearanceする必要があることに注意してくださいNO


2
私はあなたと同じ問題を抱えていますが、ルートビューコントローラーを設定していません。一体どうやってそれを見つけたの?
trgoofi 2013

1
私はフレームワークの何かが通知を受け取っていないのではないかと疑っていましたsetNeedsStatusBarAppearanceUpdate-この変更を行ったときに私の疑いが確認されました。
AbdullahC

2
アプリで見つけた関連する問題は、子ビューコントローラーを返すためにchildViewControllerForStatusBarStyleとchildViewControllerForStatusBarHiddenをオーバーライドしない全画面の子ビューコントローラーを備えたビューコントローラーでした。独自のビューコントローラー階層がある場合は、これらのメソッドを提供して、ステータスバーのスタイルを決定するために使用するビューコントローラーをシステムに通知する必要があります。
Jon Steinmetz 2013年

rootviewcontrollerを設定しても何も変更されません。Jonのコメントを処理する必要があります。また、setneedsstatusbarappearanceUpdateを呼び出すときは注意してください。あなたはそれを親から呼び出して働くべきです。
doozMen 14

1
@Hippoあなたは天才です!! rootviewcontrollerを設定していないことが原因であるとどうしてわかりましたか?
ViruMax 2014年

1019

UINavigationControllerを使用している場合:

UINavigationController転送しませんpreferredStatusBarStyleその子ビューコントローラへの呼び出し。代わりに、それは独自の状態を管理します-本来のように、ステータスバーが存在する画面の上部に描画されるため、ステータスバーに責任があります。そのためpreferredStatusBarStyle、navコントローラー内のVCに実装しても何も起こりません-それらが呼び出されることはありません。

トリックは何UINavigationControllerのために返却するかを決定するために使用していますUIStatusBarStyleDefaultUIStatusBarStyleLightContent。これは、これに基づいていUINavigationBar.barStyleます。デフォルト(UIBarStyleDefault)では、フォアグラウンドのUIStatusBarStyleDefaultステータスバーが暗くなります。そしてUIBarStyleBlack与えるUIStatusBarStyleLightContentステータスバーを。

TL; DR:

あなたがしたい場合UIStatusBarStyleLightContentUINavigationController使用:

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

59
いいね!ことを注意preferredStatusBarStyleします(設定ナビゲーションバー非表示にした場合、実際には意志が、子ビューコントローラに呼び出されるnavigationBarHiddenまでにYES)正確に、必要に応じて、。
Patrick Pijnappel 2013

25
この回答をありがとう。すべてのナビゲーションバーのbarStyleを設定する場合は、次の番号に電話してください[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]
Thomas Desert

15
完璧な答え。SOに関する他の回答では、UINavigationControllerは考慮されていません。キーボードに頭をぶつけて2時間。
Ryan Alford

10
navigationBarHiddenset YESが実際に呼び出されたことを示す@Patrickへの称賛preferredStatusBarStyleと、これにつまずく可能性のある人への警告:で動作しますnavigationBarHiddenが、navigationBar.hidden!では動作しません。
jcaron 14

4
当然のことですが、これを機能させるには、Info.plistで「View controller-based status bar appear」をYESに設定する必要もあります。
Code Baller、2015年

99

だから私は実際にカテゴリをUINavigationControllerに追加しましたが、メソッドを使用しました:

-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;

現在表示されているUIViewControllerを返します。これにより、現在表示されているView Controllerが独自の優先スタイル/可視性を設定できます。

これの完全なコードスニペットは次のとおりです。

Swiftの場合:

extension UINavigationController {

    public override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return self.topViewController
    }

    public override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return self.topViewController
    }
}

Objective-Cの場合:

@interface UINavigationController (StatusBarStyle)

@end

@implementation UINavigationController (StatusBarStyle)

-(UIViewController *)childViewControllerForStatusBarStyle {
    return self.topViewController;
}

-(UIViewController *)childViewControllerForStatusBarHidden {
    return self.topViewController;
}

@end

そして、適切な方法として、UIViewControllerに実装する方法を次に示します。

スウィフトで

override public func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

override func prefersStatusBarHidden() -> Bool {
    return false
}

Objective-Cの場合

-(UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent; // your own style
}

- (BOOL)prefersStatusBarHidden {
    return NO; // your own visibility code
}

最後に、アプリのplistの[View controller-based status bar appear ]がNOに設定されていないことを確認してください。その行を削除するか、YESに設定します(これはiOS 7のデフォルトであると思いますか?)


return self.topViewController;私には効果があるように見えますが、そうでreturn self.visibleViewController;はありません
k06a 2014年

visibleViewControllerを閉じると、現在表示されているモーダルコントローラーを返すことができます。残念です。topViewControllerを使用します。
Ben Sinclair

1
@ d.lebedevは大丈夫ですが、これらの問題はここでは当てはまらないと思います。superこのメソッドを呼び出す必要はなく、実際にこのタイプのすべてのコントローラーの動作を変更したい
ed '

1
これはiOS 9.3では機能しません。これは問題だと思います。Cocoaクラスの多くはカテゴリを使用して実装されているため、この問題は特に重要です。オーバーライドしようとするフレームワーク定義のメソッド自体がカテゴリに実装されている可能性があるため、どの実装が優先されるかは定義されていません。
vikingosegundo 2016

2
これは間違っており、iOS 13.4では機能しません。Swiftでの目的Cクラスの拡張は、目的Cカテゴリを通じて実装されるためです。Objective Cカテゴリーによるメソッドのオーバーライドは推奨されておらず、機能しなくなる可能性があります。stackoverflow.com/a/38274660/2438634を
Marc Etcheverry

79

まだこれで苦労している人にとっては、swiftのこの単純な拡張機能が問題を解決するはずです。

extension UINavigationController {
    override open var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }
}

10
あなたはメダルに値します。
nikans 2017

2
どうもありがとうございました。代わりにvisibleViewControllerを返していましたが、成功しませんでした。
ファビオ・SALATA

1
これは金です。ナビゲーションコントローラーがタブバーに埋め込まれていて、これをファイルに入れただけで、ステータスバーの外観をどこにでも変更できます。
Vahid Amiri、

2
これは間違っており、iOS 13.4では機能しません。Swiftでの目的Cクラスの拡張は、目的Cカテゴリを通じて実装されるためです。Objective Cカテゴリーによるメソッドのオーバーライドは推奨されておらず、機能しなくなる可能性があります。stackoverflow.com/a/38274660/2438634を
Marc Etcheverry

1
@MarcEtcheverryこの特定のインスタンスは間違っていませんでした。問題の事実は、UINavigationControllerなどの他のオブジェクト/プロトコルのサブクラスには、動的ディスパッチで競合するこれらのオブジェクトの以前の実装がなかったことです。実際のサブクラスにはデフォルトや実装がなかったため、これが不要な依存関係(期間)を作成せずにアプリ全体でこれを実装する最もクリーンな方法でした。残念ながら、13.4ではこの動作が変更されたようです。私は彼らが今何年も存在していないチェックまたは実装を持っている舞台裏を推測している……...
TheCodingArt

20

私のアプリは、3つのすべての使用:UINavigationControllerUISplitViewControllerUITabBarController、したがって、これらは、すべてのステータスバーの制御を取るように見えるし、原因となるpreferedStatusBarStyle子供たちのために呼び出されないように。この動作をオーバーライドするには、他の回答で述べたように拡張機能を作成できます。Swift 4での3つすべての拡張機能を次に示します。Appleがこの種のものについてもっと明確にしたいのですが。

extension UINavigationController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.topViewController
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}

extension UISplitViewController {
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return self.childViewControllers.first
    }

    open override var childViewControllerForStatusBarHidden: UIViewController? {
        return self.childViewControllers.first
    }
}

編集:Swift 4.2 API変更の更新

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.topViewController
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}

extension UISplitViewController {
    open override var childForStatusBarStyle: UIViewController? {
        return self.children.first
    }

    open override var childForStatusBarHidden: UIViewController? {
        return self.children.first
    }
}

1
これが機能する唯一のソリューションです。SOに関するすべての回答は、NavigationControllersを使用するアプリでは機能しない標準ソリューションを指します。ありがとうございました!!!
Houman

オーバーライドに拡張機能を使用するのは間違っています。それは安全ではありません。より簡単な解決策は複数あります。代わりにサブクラスを使用してください。
スルタン

2
これは間違っており、iOS 13.4では機能しません。Swiftでの目的Cクラスの拡張は、目的Cカテゴリを通じて実装されるためです。Objective Cカテゴリーによるメソッドのオーバーライドは推奨されておらず、機能しなくなる可能性があります。stackoverflow.com/a/38274660/2438634を
Marc Etcheverry

1
@MarcEtcheverryこの特定のインスタンスは間違っていませんでした。問題の事実は、UINavigationControllerなどの他のオブジェクト/プロトコルのサブクラスには、動的ディスパッチで競合するこれらのオブジェクトの以前の実装がなかったことです。実際のサブクラスにはデフォルトや実装がなかったため、これが不要な依存関係(期間)を作成せずにアプリ全体でこれを実装する最もクリーンな方法でした。残念ながら、13.4ではこの動作が変更されたようです。私は彼らが今何年も存在していないチェックまたは実装を持っている舞台裏を推測している……...
TheCodingArt

15

タイソンの答えは、ステータスバーの色をで白に変更するのに適していますUINavigationController

誰かがコードを書き込んで同じ結果を達成したい場合はAppDelegate、以下のコードを使用してAppDelegate's didFinishLaunchingWithOptionsメソッド内に記述してください。

また、.plistファイルでUIViewControllerBasedStatusBarAppearanceto を設定することを忘れないでください。そうしないYESと、変更が反映されません。

コード

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // status bar appearance code
     [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

     return YES;
}

14

UINavigationControllerではpreferredStatusBarStyletopViewControllerが推奨されるため呼び出されませんself。したがって、preferredStatusBarStyleUINavigationControllerで呼び出されるようにするには、そのを変更する必要がありますchildViewControllerForStatusBarStyle

勧告

クラスのUINavigationControllerをオーバーライドします。

class MyRootNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

非推奨の代替

すべてのUINavigationControllerに対してこれを行うには、拡張機能でオーバーライドできます(警告:UIDocumentPickerViewController、UIImagePickerControllerなどに影響します)。

extension UINavigationController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    open override var childViewControllerForStatusBarStyle: UIViewController? {
        return nil
    }
}

11

セレンの答えに加えて、ビューコントローラーにmodalPresentationStyle(たとえば.overCurrentContext)を提示している場合は、新しく提示されたビューコントローラーでもこれを呼び出す必要があります。

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

preferredStatusBarStyle表示されたビューコントローラのもオーバーライドすることを忘れないでください。


9

Hippoの回答への追加:UINavigationControllerを使用している場合は、カテゴリを追加することをお勧めします。

//  UINavigationController+StatusBarStyle.h:

@interface UINavigationController (StatusBarStyle)

@end



//  UINavigationController+StatusBarStyle.m:

@implementation UINavigationController (StatusBarStyle)

- (UIStatusBarStyle)preferredStatusBarStyle
{
    //also you may add any fancy condition-based code here
    return UIStatusBarStyleLightContent;
}

@end

そのソリューションはおそらく、廃止予定の動作に切り替えるよりも優れています。


これを行わないでください。今のところ機能しますが、将来の動作が壊れる可能性があります。navBarスタイルを変更するだけです-私の回答を参照してくださいstackoverflow.com/a/19513714/505457
Tyson

2
カテゴリではなく、サブクラスを使用する必要があります。
shuiyouren 2013年

2Tyson:なぜ将来の行動を壊すのですか?preferredStatusBarStyle:は、ステータスバーのスタイルを設定するためにAppleが推奨するメソッドです。
Artem Abramov 2013年

2shuiyouren:単にカテゴリを使用して、すべての場所に含めることができるのに、サブクラス化によって複雑さを増やす必要があるのはなぜですか?とにかく、それは実装の問題ではなく、アーキテクチャの問題です。
Artem Abramov 2013年

2
@ArtemAbramov UINavigationControllerはすでにpreferredStatusBarStyleUINavigationController固有のロジックを実装および実行しているためです。現在、このロジックはベースになってnavigationBar.barStyleいますが、追加のチェックが追加されUISearchDisplayControllerているのがわかります(たとえば、ナビゲーションバーモードを非表示に移動する)。デフォルトのロジックを上書きすることで、この機能をすべて失い、将来の迷惑な「wtf」の瞬間に備えて自分自身を開いたままにします。組み込みのナビゲーションコントローラーの動作をサポートしながら、これを行う正しい方法については、上記の私の回答を参照してください。
タイソン

9

Swift 4.2以降

選択した回答で述べたように、根本的な原因はウィンドウのルートビューコントローラーオブジェクトを確認することです。

フロー構造の考えられるケース

  • カスタムUIViewControllerオブジェクトはウィンドウルートビューコントローラーです。

    ウィンドウルートビューコントローラーはUIViewControllerオブジェクトであり、アプリケーションフローに基づいてナビゲーションコントローラーまたはtabControllerを追加または削除します。

    この種類のフローは通常、アプリにタブのないナビゲーションスタックのログイン前フローとタブのあるログイン後フローがあり、場合によってはすべてのタブがナビゲーションコントローラーをさらに保持している場合に使用されます。

  • TabBarControllerオブジェクトはウィンドウルートビューコントローラーです

    これは、ウィンドウルートビューコントローラーがtabBarControllerであるフローです。

  • NavigationControllerオブジェクトはウィンドウルートビューコントローラです

    これは、ウィンドウルートビューコントローラがnavigationControllerであるフローです。

    既存のナビゲーションコントローラーにタブバーコントローラーまたは新しいナビゲーションコントローラーを追加する可能性があるかどうかはわかりません。ただし、そのような場合は、ステータスバーのスタイルコントロールを次のコンテナに渡す必要があります。そこで、同じチェックをUINavigationController拡張機能に追加して、childForStatusBarStyle

以下の拡張機能を使用して、上記のすべてのシナリオを処理します -

extension UITabBarController {
    open override var childForStatusBarStyle: UIViewController? {
        return selectedViewController?.childForStatusBarStyle ?? selectedViewController
    }
}

extension UINavigationController {
    open override var childForStatusBarStyle: UIViewController? {
        return topViewController?.childForStatusBarStyle ?? topViewController
    }
}

extension AppRootViewController {
    open override var preferredStatusBarStyle: UIStatusBarStyle {
        return children.first { $0.childForStatusBarStyle != nil }?.childForStatusBarStyle?.preferredStatusBarStyle ?? .default
    }
}
  • デフォルトではtrue UIViewControllerBasedStatusBarAppearanceであるため、キー入力は必要ありません。info.plist

より複雑なフローについて考慮すべき点

  • 新しいフローをモーダルで表示する場合、既存のステータスバースタイルのフローから切り離されます。したがって、を提示してNewFlowUIViewControllerから、新しいナビゲーションまたはtabBarコントローラーをNewFlowUIViewControllerに追加し、さらにの拡張を追加して、NewFlowUIViewControllerビューコントローラーのステータスバースタイルをさらに管理するとします。

  • モーダル表示以外のときにmodalPresentationStyleを設定する場合は、trueにfullScreen設定modalPresentationCapturesStatusBarAppearanceして、表示されるビューコントローラーがステータスバーの外観コントロールを受け取るようにする必要があります。


正解です。
アミンベナリエブ

3
これは間違っており、iOS 13.4では機能しません。Swiftでの目的Cクラスの拡張は、目的Cカテゴリを通じて実装されるためです。Objective Cカテゴリーによるメソッドのオーバーライドは推奨されておらず、機能しなくなる可能性があります。stackoverflow.com/a/38274660/2438634を
Marc Etcheverry

@MarcEtcheverryこの特定のインスタンスは間違っていませんでした。問題の事実は、UINavigationControllerなどの他のオブジェクト/プロトコルのサブクラスには、動的ディスパッチで競合するこれらのオブジェクトの以前の実装がなかったことです。実際のサブクラスにはデフォルトや実装がなかったため、これが不要な依存関係(期間)を作成せずにアプリ全体でこれを実装する最もクリーンな方法でした。残念ながら、13.4ではこの動作が変更されたようです。私は彼らが今何年も存在していないチェックまたは実装を持っている舞台裏を推測している... ...
TheCodingArt

8

iOS 13ソリューション

UINavigationControllerUIViewController(whoを知っている)のサブクラスです!

したがって、ナビゲーションコントローラーに埋め込まれたビューコントローラーを提示する場合、埋め込まれたビューコントローラーは実際には提示されません。あなたはナビゲーションコントローラーを提示しています!UINavigationController、のサブクラスとしてUIViewControllerpreferredStatusBarStyleおよびを継承しchildForStatusBarStyle、必要に応じて設定できます。

次のいずれかの方法が機能するはずです。

  1. ダークモードを完全に無効にする
    • info.plist、次のプロパティを追加します。
      • キー- UIUserInterfaceStyle(別名。「ユーザーインターフェイススタイル」)
      • 価値-光
  2. preferredStatusBarStyle内でオーバーライドUINavigationController

    • preferredStatusBarStyledoc)-ビューコントローラの優先ステータスバースタイル
    • サブクラスまたは拡張 UINavigationController

      class MyNavigationController: UINavigationController {
          override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }

      または

      extension UINavigationController {
          open override var preferredStatusBarStyle: UIStatusBarStyle {
              .lightContent
          }
      }
  3. childForStatusBarStyle内でオーバーライドUINavigationController

    • childForStatusBarStyleドキュメント)-システムがステータスバーのスタイルを決定するために使用するビューコントローラーが必要なときに呼び出されます
    • Appleのドキュメントによると、

      「コンテナービューコントローラーがその子ビューコントローラーの1つからステータスバースタイルを派生している場合、[このプロパティをオーバーライドして]その子ビューコントローラーを返します。nilを返すか、このメソッドをオーバーライドしない場合は、セルフのステータスバースタイルが使用されます。このメソッドからの戻り値が変更された場合は、setNeedsStatusBarAppearanceUpdate()メソッドを呼び出します。

    • つまり、ここでソリューション3を実装しない場合、システムは上記のソリューション2にフォールバックします。
    • サブクラスまたは拡張 UINavigationController

      class MyNavigationController: UINavigationController {
          override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }

      または

      extension UINavigationController {    
          open override var childForStatusBarStyle: UIViewController? {
              topViewController
          }
      }
    • 上記の任意のビューコントローラを返すことができます。次のいずれかをお勧めします。

      • topViewController(of UINavigationController)(doc)-ナビゲーションスタックの最上部にあるビューコントローラー
      • visibleViewController(of UINavigationController)(doc)-ナビゲーションインターフェースで現在表示されているビューに関連付けられているビューコントローラー(ヒント:「ナビゲーションコントローラー自体の上にモーダルに表示されたビューコントローラー」を含めることができます)

注:サブクラス化する場合はUINavigationController、IBのIDインスペクターを使用して、そのクラスをナビゲーションコントローラーに適用してください。

PS私のコードはSwift 5.1構文を使用しています😎


画面の回転後、ステータスバーが黒くなります。なぜだと思いますか?これはiPad Proシミュレータでのみ発生します。
ペドロパウロアモリム

@PedroPauloAmorim、詳細情報を提供できますか?トップビューコントローラーはどのように表示されますか(モーダル、フルスクリーン、ショー)?ナビゲーションコントローラ内にネストされていますか?テキストが黒くなったり、背景が変わったりしていませんか?あなたは何を成し遂げようとしているのですか?
Andrew Kirna

アプリ全体にライトステータスバーを設定しました。2回回転すると明るくなります。3回目は暗くなり、再描画せずに再び光に戻ることはありません。iPad Proシミュレータで起こっています。ビューはフルスクリーンで表示され、ナビゲーションコントローラ内にネストされていません。テキストだけが暗くなります。
ペドロパウロアモリム

そもそもどうやってライトステータスバーを設定するのですか?
Andrew Kirna

3
拡張機能によるオーバーライドは、実際のオーバーライドではありません。これは、言語を安全に誤用することです。それは非常に簡単に壊れる可能性があります。
スルタン

7

上記の@serennの回答は、UINavigationControllersの場合に最適です。ただし、Swift 3では、childViewController関数がに変更されましたvars。したがって、UINavigationController拡張コードは次のようになります。

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

そして、ステータスバーのスタイルを指示するビューコントローラーで:

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}

2
これは間違っており、iOS 13.4では機能しません。Swiftでの目的Cクラスの拡張は、目的Cカテゴリを通じて実装されるためです。Objective Cカテゴリーによるメソッドのオーバーライドは推奨されておらず、機能しなくなる可能性があります。stackoverflow.com/a/38274660/2438634を
Marc Etcheverry

@MarcEtcheverryこの特定のインスタンスは間違っていませんでした。問題の事実は、UINavigationControllerなどの他のオブジェクト/プロトコルのサブクラスには、動的ディスパッチで競合するこれらのオブジェクトの以前の実装がなかったことです。実際のサブクラスにはデフォルトや実装がなかったため、これが不要な依存関係(期間)を作成せずにアプリ全体でこれを実装する最もクリーンな方法でした。残念ながら、13.4ではこの動作が変更されたようです。私は彼らが今何年も存在していないチェックまたは実装を持っている舞台裏を推測している... ...
TheCodingArt

6

viewControllerがUINavigationControllerの下にある場合。

UINavigationControllerをサブクラス化して追加

override var preferredStatusBarStyle: UIStatusBarStyle {
    return topViewController?.preferredStatusBarStyle ?? .default
}

ViewController preferredStatusBarStyleが呼び出されます。


1
この投稿を参照してください。medium.com
Harry Bloom

4

iOS 7のUIStatusBarStyle

iOS 7のステータスバーは透明で、背後のビューが透けて見えます。

ステータスバーのスタイルは、コンテンツの外観を表します。iOS 7では、ステータスバーのコンテンツは暗い(UIStatusBarStyleDefault)または明るい(UIStatusBarStyleLightContent)です。UIStatusBarStyleBlackTranslucentUIStatusBarStyleBlackOpaqueは両方ともiOS 7.0では非推奨です。UIStatusBarStyleLightContent代わりに使用してください。

変更方法 UIStatusBarStyle

ステータスバーの下がナビゲーションバーである場合、ステータスバーのスタイルは、ナビゲーションバーのスタイル(UINavigationBar.barStyle)と一致するように調整されます。

具体的には、ナビゲーションバーのスタイルがUIBarStyleDefaultの場合、ステータスバーのスタイルはになりUIStatusBarStyleDefaultます。ナビゲーションバーのスタイルがのUIBarStyleBlack場合、ステータスバーのスタイルはになりますUIStatusBarStyleLightContent

ステータスバーの下にナビゲーションバーがない場合、ステータスバーのスタイルは、アプリの実行中に個々のビューコントローラーによって制御および変更できます。

- [UIViewController preferredStatusBarStyle]優先ステータスバーのスタイルを返すようにオーバーライドすることができiOSの7で追加された新しい方法です。

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

ステータスバーのスタイルを自分ではなく子ビューコントローラーで制御する必要がある場合は、オーバーライド-[UIViewController childViewControllerForStatusBarStyle]してその子ビューコントローラーを返します。

この動作をオプトアウトし、-[UIApplication statusBarStyle]メソッドを使用してステータスバーのスタイルを設定する場合はUIViewControllerBasedStatusBarAppearance、アプリのInfo.plistファイルにキーを追加して、値をNOにします。


3

誰かがナビゲーションコントローラーを使用していて、すべてのナビゲーションコントローラーを黒のスタイルにしたい場合は、Swift 3でこのようにUINavigationControllerに拡張機能を記述して、すべてのナビゲーションコントローラーに適用できます(時間)。

extension UINavigationController {

    override open func viewDidLoad() {
        super.viewDidLoad()

        self.navigationBar.barStyle = UIBarStyle.black
    }

}

1
しかし、ナビゲーションバーが非表示になっている場合はどうなりますか?
Slavcho 2017年

1
ナビゲーションを非表示にし、ステータスバーを表示する必要があるためです。
Slavcho 2017年

1

あらゆる種類のUIViewControllerのSwift:

あなたの中にAppDelegateセット:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    window!.rootViewController = myRootController
    return true
}

myRootControllerUIViewControllerたとえば、UITabBarControllerまたはのような、任意の種類を使用できますUINavigationController

次に、このルートコントローラを次のようにオーバーライドします。

class RootController: UIViewController {
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }
}

これにより、アプリ全体のステータスバーの外観が変更されます。これは、ルートコントローラーがステータスバーの外観を単独で担当するためです。

これを機能させるにView controller-based status bar appearanceは、プロパティをYES に設定することを忘れないでくださいInfo.plist(これがデフォルトです)。


@ swift3ではどうですか?
航空機は

1

Swift 3 iOS 10ソリューション:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }

1

ほとんどの回答には、のchildViewControllerForStatusBarStyleメソッドの適切な実装が含まれていませんUINavigationController。私の経験によれば、ナビゲーションコントローラの上に透明なビューコントローラが表示される場合などのケースを処理する必要があります。これらの場合、モーダルコントローラー(visibleViewController)に制御を渡す必要がありますが、非表示の場合は受け渡しません。

override var childViewControllerForStatusBarStyle: UIViewController? {
  var childViewController = visibleViewController
  if let controller = childViewController, controller.isBeingDismissed {
    childViewController = topViewController
  }
  return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}

1

私の場合、私は誤って表示/ナビゲーションコントローラを発表しましたUIModalPresentationStyle.overFullScreen原因と、preferredStatusBarStyle呼び出されていません。に戻した後UIModalPresentationStyle.fullScreen、すべてが機能します。


1

iOS 13.4のpreferredStatusBarStyle場合、UINavigationControllerカテゴリ内のメソッドは呼び出されません。スウィズリングは、サブクラスを使用する必要がない唯一のオプションのようです。

例:

カテゴリーヘッダー:

@interface UINavigationController (StatusBarStyle)
+ (void)setUseLightStatusBarStyle;
@end

実装:

#import "UINavigationController+StatusBarStyle.h"
#import <objc/runtime.h>

@implementation UINavigationController (StatusBarStyle)

void (^swizzle)(Class, SEL, SEL) = ^(Class c, SEL orig, SEL new){
    Method origMethod = class_getInstanceMethod(c, orig);
    Method newMethod = class_getInstanceMethod(c, new);
    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
};

+ (void)setUseLightStatusBarStyle {
    swizzle(self.class, @selector(preferredStatusBarStyle), @selector(_light_preferredStatusBarStyle));
}

- (UIStatusBarStyle)_light_preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}    
@end

AppDelegate.hでの使用:

#import "UINavigationController+StatusBarStyle.h"

[UINavigationController setUseLightStatusBarStyle];

0

これを解決するための私の方法は次のとおりです。

AGViewControllerAppearanceというプロトコルを定義します。

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;

@end

UpgradeというUIViewControllerのカテゴリを定義します。

UIViewController + Upgrade.h

#import <UIKit/UIKit.h>

@interface UIViewController (Upgrade)

//
//  Replacements
//

- (void)upgradedViewWillAppear:(BOOL)animated;

@end

UIViewController + Upgrade.m

#import "UIViewController+Upgrade.h"

#import <objc/runtime.h>

#import "AGViewControllerAppearance.h" // This is the appearance protocol

@implementation UIViewController (Upgrade)

+ (void)load
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wselector"
    Method viewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
#pragma clang diagnostic pop
    Method upgradedViewWillAppear = class_getInstanceMethod(self, @selector(upgradedViewWillAppear:));
    method_exchangeImplementations(viewWillAppear, upgradedViewWillAppear);
}

#pragma mark - Implementation

- (void)upgradedViewWillAppear:(BOOL)animated
{
    //
    //  Call the original message (it may be a little confusing that we're
    //  calling the 'same' method, but we're actually calling the original one :) )
    //

    [self upgradedViewWillAppear:animated];

    //
    //  Implementation
    //

    if ([self conformsToProtocol:@protocol(AGViewControllerAppearance)])
    {
        UIViewController <AGViewControllerAppearance> *viewControllerConformingToAppearance =
        (UIViewController <AGViewControllerAppearance> *)self;

        //
        //  Status bar
        //

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(preferredStatusBarStyle)])
        {
            BOOL shouldAnimate = YES;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(animatesStatusBarVisibility)])
            {
                shouldAnimate = [viewControllerConformingToAppearance animatesStatusBarVisibility];
            }

            [[UIApplication sharedApplication] setStatusBarStyle:[viewControllerConformingToAppearance preferredStatusBarStyle]
                                                        animated:shouldAnimate];
        }

        if ([viewControllerConformingToAppearance respondsToSelector:@selector(showsStatusBar)])
        {
            UIStatusBarAnimation animation = UIStatusBarAnimationSlide;

            if ([viewControllerConformingToAppearance respondsToSelector:@selector(prefferedStatusBarAnimation)])
            {
                animation = [viewControllerConformingToAppearance prefferedStatusBarAnimation];
            }

            [[UIApplication sharedApplication] setStatusBarHidden:(! [viewControllerConformingToAppearance showsStatusBar])
                                                    withAnimation:animation];
        }
    }
}

@end

ここで、ビューコントローラーがAGViewControllerAppearanceプロトコルを実装していると言います。

例:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

もちろん、あなたがメソッド(の残りの部分を実装することができshowsStatusBaranimatesStatusBarVisibilityprefferedStatusBarAnimationプロトコルやから)のUIViewControllerを+アップグレードそれらによって提供された値に基づいて適切なカスタマイズを行います。


0

UISearchControllerでこの問題が発生した場合。UISearchControllerの新しいサブクラスを作成し、そのクラスに以下のコードを追加するだけです。

override func preferredStatusBarStyle() -> UIStatusBarStyle {
    return .LightContent
}

0

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;ソリューションを使用するときは注意してください

必ずplistに移動し、「コントローラーベースのステータスバーの外観の表示」をYESに設定してください。NOの場合は機能しません。


プロジェクトplistでUIViewControllerBasedStatusBarAppearanceをYESに設定すると、すべての違いが生まれました。私はそれを忘れていました。
filo、

0

Xcode 11.4以降preferredStatusBarStyle、UINavigationController拡張機能のプロパティのオーバーライドは呼び出されないため機能しなくなりました。

設定barStyleのをnavigationBar.black実際に動作しますが、あなたは光と闇モードの異なる外観を有することができるnavigationBarにサブビューを追加する場合、これは望ましくない副作用を追加します。barStyleを黒に設定することによりuserInterfaceStyle、navigationBarに埋め込まれたビューuserInterfaceStyle.darkuserInterfaceStyleは、アプリのに関係なく常に持つことになります。

私が思いついた適切な解決策は、のサブクラスを追加してUINavigationControllerオーバーライドするpreferredStatusBarStyleことです。次に、このカスタムUINavigationControllerをすべてのビューに使用すると、保存側になります。


-1

NavigationControllerまたはTabBarControllerは、スタイルを提供する必要があるものです。これが私が解決した方法です:https//stackoverflow.com/a/39072526/242769


これが別の質問の重複であると思われる場合は、重複として投票してください
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.