私は、その後、このスレッドをオーバーライドする-preferredStatusBarStyle
が、それは呼び出されません。それを有効にするために変更できるオプションはありますか?(プロジェクトでXIBを使用しています。)
私は、その後、このスレッドをオーバーライドする-preferredStatusBarStyle
が、それは呼び出されません。それを有効にするために変更できるオプションはありますか?(プロジェクトでXIBを使用しています。)
回答:
同じ問題があり、アプリケーションウィンドウでルートビューコントローラーを設定していなかったために発生していることがわかりました。
で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;
}
または、を使用する代わりに、背景色に応じて、各View Controllerで次のメソッドのいずれかを適宜呼び出すことができますsetNeedsStatusBarAppearanceUpdate
。
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
または
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
この方法を使用する場合は、plistファイルにもを設定UIViewControllerBasedStatusBarAppearance
する必要があることに注意してくださいNO
。
setNeedsStatusBarAppearanceUpdate
-この変更を行ったときに私の疑いが確認されました。
UINavigationControllerを使用している場合:
UINavigationController
転送しませんpreferredStatusBarStyle
その子ビューコントローラへの呼び出し。代わりに、それは独自の状態を管理します-本来のように、ステータスバーが存在する画面の上部に描画されるため、ステータスバーに責任があります。そのためpreferredStatusBarStyle
、navコントローラー内のVCに実装しても何も起こりません-それらが呼び出されることはありません。
トリックは何UINavigationController
のために返却するかを決定するために使用していますUIStatusBarStyleDefault
かUIStatusBarStyleLightContent
。これは、これに基づいていUINavigationBar.barStyle
ます。デフォルト(UIBarStyleDefault
)では、フォアグラウンドのUIStatusBarStyleDefault
ステータスバーが暗くなります。そしてUIBarStyleBlack
与えるUIStatusBarStyleLightContent
ステータスバーを。
TL; DR:
あなたがしたい場合UIStatusBarStyleLightContent
にUINavigationController
使用:
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
preferredStatusBarStyle
します(設定ナビゲーションバー非表示にした場合、実際には意志が、子ビューコントローラに呼び出されるnavigationBarHidden
までにYES
)正確に、必要に応じて、。
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack]
navigationBarHidden
set YES
が実際に呼び出されたことを示す@Patrickへの称賛preferredStatusBarStyle
と、これにつまずく可能性のある人への警告:で動作しますnavigationBarHidden
が、navigationBar.hidden
!では動作しません。
だから私は実際にカテゴリを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;
はありません
super
このメソッドを呼び出す必要はなく、実際にこのタイプのすべてのコントローラーの動作を変更したい
まだこれで苦労している人にとっては、swiftのこの単純な拡張機能が問題を解決するはずです。
extension UINavigationController {
override open var childForStatusBarStyle: UIViewController? {
return self.topViewController
}
}
私のアプリは、3つのすべての使用:UINavigationController
、UISplitViewController
、UITabBarController
、したがって、これらは、すべてのステータスバーの制御を取るように見えるし、原因となる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
}
}
タイソンの答えは、ステータスバーの色をで白に変更するのに適していますUINavigationController
。
誰かがコードを書き込んで同じ結果を達成したい場合はAppDelegate
、以下のコードを使用してAppDelegate's
didFinishLaunchingWithOptions
メソッド内に記述してください。
また、.plistファイルでUIViewControllerBasedStatusBarAppearance
to を設定することを忘れないでください。そうしないYES
と、変更が反映されません。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// status bar appearance code
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
return YES;
}
UINavigationControllerではpreferredStatusBarStyle
、topViewController
が推奨されるため呼び出されませんself
。したがって、preferredStatusBarStyle
UINavigationControllerで呼び出されるようにするには、そのを変更する必要があります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
}
}
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
そのソリューションはおそらく、廃止予定の動作に切り替えるよりも優れています。
preferredStatusBarStyle
UINavigationController固有のロジックを実装および実行しているためです。現在、このロジックはベースになってnavigationBar.barStyle
いますが、追加のチェックが追加されUISearchDisplayController
ているのがわかります(たとえば、ナビゲーションバーモードを非表示に移動する)。デフォルトのロジックを上書きすることで、この機能をすべて失い、将来の迷惑な「wtf」の瞬間に備えて自分自身を開いたままにします。組み込みのナビゲーションコントローラーの動作をサポートしながら、これを行う正しい方法については、上記の私の回答を参照してください。
選択した回答で述べたように、根本的な原因はウィンドウのルートビューコントローラーオブジェクトを確認することです。
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
}
}
UIViewControllerBasedStatusBarAppearance
であるため、キー入力は必要ありません。info.plist
新しいフローをモーダルで表示する場合、既存のステータスバースタイルのフローから切り離されます。したがって、を提示してNewFlowUIViewController
から、新しいナビゲーションまたはtabBarコントローラーをNewFlowUIViewController
に追加し、さらにの拡張を追加して、NewFlowUIViewController
ビューコントローラーのステータスバースタイルをさらに管理するとします。
モーダル表示以外のときにmodalPresentationStyleを設定する場合は、trueにfullScreen
設定modalPresentationCapturesStatusBarAppearance
して、表示されるビューコントローラーがステータスバーの外観コントロールを受け取るようにする必要があります。
UINavigationController
UIViewController
(whoを知っている)のサブクラスです!
したがって、ナビゲーションコントローラーに埋め込まれたビューコントローラーを提示する場合、埋め込まれたビューコントローラーは実際には提示されません。あなたはナビゲーションコントローラーを提示しています!UINavigationController
、のサブクラスとしてUIViewController
、preferredStatusBarStyle
およびを継承しchildForStatusBarStyle
、必要に応じて設定できます。
次のいずれかの方法が機能するはずです。
info.plist
、次のプロパティを追加します。
UIUserInterfaceStyle
(別名。「ユーザーインターフェイススタイル」)preferredStatusBarStyle
内でオーバーライドUINavigationController
preferredStatusBarStyle
(doc)-ビューコントローラの優先ステータスバースタイルサブクラスまたは拡張 UINavigationController
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
または
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
childForStatusBarStyle
内でオーバーライドUINavigationController
childForStatusBarStyle
(ドキュメント)-システムがステータスバーのスタイルを決定するために使用するビューコントローラーが必要なときに呼び出されます「コンテナービューコントローラーがその子ビューコントローラーの1つからステータスバースタイルを派生している場合、[このプロパティをオーバーライドして]その子ビューコントローラーを返します。nilを返すか、このメソッドをオーバーライドしない場合は、セルフのステータスバースタイルが使用されます。このメソッドからの戻り値が変更された場合は、setNeedsStatusBarAppearanceUpdate()メソッドを呼び出します。
サブクラスまたは拡張 UINavigationController
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
または
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
上記の任意のビューコントローラを返すことができます。次のいずれかをお勧めします。
注:サブクラス化する場合はUINavigationController
、IBのIDインスペクターを使用して、そのクラスをナビゲーションコントローラーに適用してください。
PS私のコードはSwift 5.1構文を使用しています😎
上記の@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
}
viewControllerがUINavigationControllerの下にある場合。
UINavigationControllerをサブクラス化して追加
override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
ViewController preferredStatusBarStyle
が呼び出されます。
iOS 7のUIStatusBarStyle
iOS 7のステータスバーは透明で、背後のビューが透けて見えます。
ステータスバーのスタイルは、コンテンツの外観を表します。iOS 7では、ステータスバーのコンテンツは暗い(UIStatusBarStyleDefault
)または明るい(UIStatusBarStyleLightContent
)です。UIStatusBarStyleBlackTranslucent
とUIStatusBarStyleBlackOpaque
は両方とも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にします。
誰かがナビゲーションコントローラーを使用していて、すべてのナビゲーションコントローラーを黒のスタイルにしたい場合は、Swift 3でこのようにUINavigationControllerに拡張機能を記述して、すべてのナビゲーションコントローラーに適用できます(時間)。
extension UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.barStyle = UIBarStyle.black
}
}
あらゆる種類の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
は、プロパティをYES に設定することを忘れないでくださいInfo.plist
(これがデフォルトです)。
ほとんどの回答には、のchildViewControllerForStatusBarStyle
メソッドの適切な実装が含まれていませんUINavigationController
。私の経験によれば、ナビゲーションコントローラの上に透明なビューコントローラが表示される場合などのケースを処理する必要があります。これらの場合、モーダルコントローラー(visibleViewController
)に制御を渡す必要がありますが、非表示の場合は受け渡しません。
override var childViewControllerForStatusBarStyle: UIViewController? {
var childViewController = visibleViewController
if let controller = childViewController, controller.isBeingDismissed {
childViewController = topViewController
}
return childViewController?.childViewControllerForStatusBarStyle ?? childViewController
}
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];
これを解決するための私の方法は次のとおりです。
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
もちろん、あなたがメソッド(の残りの部分を実装することができshowsStatusBar、animatesStatusBarVisibility、prefferedStatusBarAnimationプロトコルやから)のUIViewControllerを+アップグレードそれらによって提供された値に基づいて適切なカスタマイズを行います。
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
ソリューションを使用するときは注意してください
必ずplistに移動し、「コントローラーベースのステータスバーの外観の表示」をYESに設定してください。NOの場合は機能しません。
Xcode 11.4以降preferredStatusBarStyle
、UINavigationController拡張機能のプロパティのオーバーライドは呼び出されないため機能しなくなりました。
設定barStyle
のをnavigationBar
に.black
実際に動作しますが、あなたは光と闇モードの異なる外観を有することができるnavigationBarにサブビューを追加する場合、これは望ましくない副作用を追加します。barStyle
を黒に設定することによりuserInterfaceStyle
、navigationBarに埋め込まれたビューuserInterfaceStyle.dark
のuserInterfaceStyle
は、アプリのに関係なく常に持つことになります。
私が思いついた適切な解決策は、のサブクラスを追加してUINavigationController
オーバーライドするpreferredStatusBarStyle
ことです。次に、このカスタムUINavigationControllerをすべてのビューに使用すると、保存側になります。
NavigationControllerまたはTabBarControllerは、スタイルを提供する必要があるものです。これが私が解決した方法です:https://stackoverflow.com/a/39072526/242769