web-dev-qa-db-ja.com

preferredStatusBarStyleが呼び出されていません

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

235
trgoofi

考えられる根本的な原因

私は同じ問題を抱えていて、私は自分のアプリケーションウィンドウでルートView Controllerを設定していなかったのでそれが起こっていることを理解しました。

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

このUITabBarControllerを指すようにルートView Controllerを設定すると、ステータスバーの変更が正しく機能し始めました(そして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では非推奨)

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

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

または

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

この方法を使用する場合は、plistファイルでUIViewControllerBasedStatusBarAppearanceNOに設定する必要もあります。

113
AbdullahC

INavigationControllerを使っている人のために:

UINavigationControllerは、その子View ControllerへのpreferredStatusBarStyleの呼び出しを転送しません。その代わりにそれはそれ自身の状態を管理します - それは本来あるべきように、それはステータスバーが存在するスクリーンの一番上に描いているのでそれに責任があるべきです。そのため、navコントローラ内のあなたのVCにpreferredStatusBarStyleを実装することは何もしないでしょう - それらは決して呼ばれないでしょう。

トリックは、UINavigationControllerUIStatusBarStyleDefaultまたはUIStatusBarStyleLightContentに何を返すかを決定するために使用するものです。これはUINavigationBar.barStyleに基づいています。デフォルト(UIBarStyleDefault)では、暗い前景のUIStatusBarStyleDefaultステータスバーが表示されます。そしてUIBarStyleBlackUIStatusBarStyleLightContentステータスバーを与えます。

TL; DR:

UIStatusBarStyleLightContentUINavigationControllerが必要な場合は、次のようにします。

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
975
Tyson

だから私は実際に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に実装されている方法は次のとおりです。

Swiftでは

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が動作することを確認してくださいNOT "View controller-based status bar appearance"をNOに設定してください。その行を削除するか、それをYESに設定してください(私は今iOS 7のデフォルトであると思いますか?)

95
serenn

まだこれに苦しんでいる人のために、Swiftのこの単純な拡張はあなたのために問題を解決するべきです。

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

Tyson'sUINavigationControllerでステータスバーの色を白に変更するのは正しい答えです。

誰かがAppDelegateにコードを書くことによって同じ結果を達成したいならば、以下のコードを使って、そしてそれをAppDelegate'sdidFinishLaunchingWithOptionsメソッドの中に書く。

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

コード

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

     return YES;
}
15
Yogesh Suthar

私のアプリはUINavigationControllerUISplitViewControllerUITabBarControllerの3つすべてを使用していたので、これらはすべてステータスバーを制御しているように見え、preferedStatusBarStyleが子に対して呼び出されないようにします。この振る舞いを無効にするために、残りの答えが述べたように拡張を作成することができます。これがSwift 4の3つすべての拡張です。Wish 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
    }
}
11
Luis

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

その解決策は、近いうちに廃止予定の動作に切り替えるよりもおそらく優れています。

9
Artem Abramov

UINavigationControllerでは、preferredStatusBarStyletopViewControllerよりも優先されるため、selfは呼び出されません。そのため、UINavigationControllerでpreferredStatusBarStyleを呼び出すには、そのchildViewControllerForStatusBarStyleを変更する必要があります。

1つの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
    }
}
8
Cœur

@ serennの answer は、UINavigationControllersの場合にはまだ優れたものです。しかし、Swift 3では、childViewController関数はvarsに変更されました。そのため、UINavigationController拡張コードは次のようになります。

override open var childViewControllerForStatusBarStyle: UIViewController? {
  return topViewController
}

override open var childViewControllerForStatusBarHidden: UIViewController? {
  return topViewController
}

そして、ステータスバーのスタイルを指示するべきView Controllerで:

override var preferredStatusBarStyle: UIStatusBarStyle {
   return .lightContent
}
8
John Stricker

あなたのviewControllerがUINavigationControllerの下にある場合。

サブクラスUINavigationControllerと追加

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

ViewControllerのpreferredStatusBarStyleが呼び出されます。

5
PowHu

Serennの回答に加えて、modalPresentationStylename__(例えば.overCurrentContext)を付けてView Controllerを表示している場合は、新しく表示されたView Controllerでこれを呼び出す必要があります。

presentedViewController.modalPresentationCapturesStatusBarAppearance = true

表示されているView ControllerのpreferredStatusBarStylename__もオーバーライドすることを忘れないでください。

5
frin

Swift 4.2以降

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

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

  • カスタムUIViewControllerオブジェクトはウィンドウルートView Controllerです

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

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

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

    これは、ウィンドウルートビューコントローラーがtabBarControllerであり、おそらくすべてのタブがさらにナビゲーションコントローラーを保持するフローです。

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

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

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

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

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
    }
}
  • info.plistUIViewControllerBasedStatusBarAppearanceキーは必要ありません。デフォルトではtrueです

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

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

  • モーダル表示中にfullScreen以外のmodalPresentationStyleを設定する場合は、modalPresentationCapturesStatusBarAppearanceをtrueに設定して、表示されるView Controllerがステータスバーの外観コントロールを受け取ります。

5

iOS 7のUIStatusBarStyle

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

ステータスバーのスタイルは、そのコンテンツの外観を表します。 iOS 7では、ステータスバーの内容は濃い色(UIStatusBarStyleDefault)または薄い色(UIStatusBarStyleLightContent)です。 UIStatusBarStyleBlackTranslucentUIStatusBarStyleBlackOpaqueはどちらもiOS 7.0では非推奨です。代わりにUIStatusBarStyleLightContentを使用してください。

UIStatusBarStyleを変更する方法

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

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

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

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

- (UIStatusBarStyle)preferredStatusBarStyle
  {
      return UIStatusBarStyleLightContent;
  }

ステータスバーのスタイルをselfではなく子のView Controllerで制御する必要がある場合は、-[UIViewController childViewControllerForStatusBarStyle]をオーバーライドしてその子のView Controllerを返します。

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

4
oscarr

誰かがNavigation Controllerを使用していて、すべてのNavigation Controllerを黒スタイルにしたい場合は、Swift 3でこのようにUINavigationControllerに拡張機能を記述することができます。時間)。

extension UINavigationController {

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

        self.navigationBar.barStyle = UIBarStyle.black
    }

}
4
Benjamin Lowry

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

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
 }
1
Statik

誰かがUISearchControllerでこの問題に遭遇した場合。 UISearchControllerの新しいサブクラスを作成し、そのクラスに以下のコードを追加してください。

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

あらゆる種類のUIViewControllerのSwiftでは

AppDelegateセットで:

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

myRootControllerはどんな種類のUIViewControllerでも構いません。 UITabBarControllerまたはUINavigationController

次に、このルートコントローラを次のように上書きします。

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

ルートコントローラがステータスバーの外観にのみ責任を持つため、これはアプリケーション全体のステータスバーの外観を変更します。

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

0
Damnum

ほとんどの回答には、childViewControllerForStatusBarStyleに対するUINavigationControllerメソッドの適切な実装は含まれていません。私の経験によれば、透明なView ControllerがNavigation Controllerの上に表示される場合などに対処する必要があります。このような場合は、モーダルコントローラー(visibleViewController)に制御を渡す必要がありますが、表示されなくなったときはそうしないでください。

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

これを解決するための私の方法です。

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

AGViewControllerAppearance.h

#import <Foundation/Foundation.h>

@protocol AGViewControllerAppearance <NSObject>

@optional

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

@end

IViewControllerと呼ばれるpgradeでカテゴリを定義します。

IViewController + Upgrade.h

#import <UIKit/UIKit.h>

@interface UIViewController (Upgrade)

//
//  Replacements
//

- (void)upgradedViewWillAppear:(BOOL)animated;

@end

IViewController + 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

さて、あなたはView ControllerがAGViewControllerAppearanceプロトコルを実装していると言う時が来ました。

例:

@interface XYSampleViewController () <AGViewControllerAppearance>

... the rest of the interface

@end

もちろん、残りのメソッド(showsStatusBaranimatesStatusBarVisibilityprefferedStatusBarAnimation)をプロトコルから実装することも、IViewController + Upgrade]はそれらが提供する値に基づいて適切なカスタマイズを行います。

0
arturgrigor

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

必ずplistに行き、 "View controller-based status bar appearance"をYESに設定してください。いいえの場合それは動作しません。

0