我遵循这个线程重写-preferredStatusBarStyle,但它没有被调用。 有什么选项我可以改变来启用它吗?(我在我的项目中使用xib。)
当前回答
对于iOS 13.4, UINavigationController类别中的preferredStatusBarStyle方法将不会被调用,swizzling似乎是唯一的选择,不需要使用子类。
例子:
分类标题:
@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];
其他回答
从Xcode 11.4开始,覆盖UINavigationController扩展中的preferredStatusBarStyle属性不再有效,因为它将不会被调用。
将navigationBar的barStyle设置为.black确实有效,但如果你向navigationBar添加子视图,它可能在明暗模式下具有不同的外观,则会添加不必要的副作用。因为通过将barStyle设置为黑色,嵌入在navigationBar中的视图的userInterfaceStyle将始终具有userInterfaceStyle。不管应用程序的userinterfacstyle是暗的。
我提出的正确解决方案是通过添加UINavigationController的子类并覆盖preferredStatusBarStyle。如果你使用这个自定义的UINavigationController为你所有的视图,你将在保存侧。
这是我解决这个问题的方法。
定义一个名为AGViewControllerAppearance的协议。
AGViewControllerAppearance.h
#import <Foundation/Foundation.h>
@protocol AGViewControllerAppearance <NSObject>
@optional
- (BOOL)showsStatusBar;
- (BOOL)animatesStatusBarVisibility;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIStatusBarAnimation)prefferedStatusBarAnimation;
@end
在UIViewController上定义一个名为Upgrade的类别。
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, prefereredstatusbaranimation)从协议和UIViewController+升级将做适当的 基于它们提供的值进行定制。
@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
}
所以我实际上添加了一个category到UINavigationController,但是使用了这些方法:
-(UIViewController *)childViewControllerForStatusBarStyle;
-(UIViewController *)childViewControllerForStatusBarHidden;
让它们返回当前可见的UIViewController。这让当前可见视图控制器设置它自己的首选样式/可见性。
下面是它的完整代码片段:
迅速:
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
}
最后,确保你的app plist没有将“基于视图控制器的状态栏外观”设置为NO。要么删除这一行,要么将其设置为YES(我相信这是iOS 7的默认设置?)
在UINavigationController上,preferredStatusBarStyle不会被调用,因为它的topViewController优先于self。所以,要在UINavigationController上调用preferredStatusBarStyle,你需要改变它的childForStatusBarStyle (Swift) / childViewControllerForStatusBarStyle (ObjC)。
建议
重写你类中的UINavigationController:
class MyRootNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var childForStatusBarStyle: UIViewController? {
return nil
}
}
非推荐替代方案
要为所有UINavigationController做这件事,你可以在一个扩展中覆盖(警告:它会影响UIDocumentPickerViewController, UIImagePickerController等),但你可能不应该根据Swift文档这样做:
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
open override var childForStatusBarStyle: UIViewController? {
return nil
}
}
推荐文章
- 我如何在我的iOS应用程序中每n分钟得到一个后台位置更新?
- 如何使用iOS创建GUID/UUID
- 禁用所呈现视图控制器的交互式撤销
- 点击按钮时如何打开手机设置?
- 如何使用UIVisualEffectView来模糊图像?
- 如何修复UITableView分隔符在iOS 7?
- 故事板中的自定义单元格行高设置没有响应
- 在Swift中使用自定义消息抛出错误/异常的最简单方法?
- 如何在Swift中获得唯一的设备ID ?
- 复制文本到剪贴板与iOS
- 在Swift中根据字符串计算UILabel的大小
- 如何调用手势点击在UIView编程在迅速
- 我如何隐藏在一个Swift iOS应用程序的状态栏?
- 在iPad上使用iOS 8正确呈现UIAlertController
- 尝试将一个非属性列表对象设置为NSUserDefaults