是否可以在 iOS 13 上选择退出暗模式?
Is it possible to opt-out of dark mode on iOS 13?
我的应用程序的很大一部分由 Web 视图组成,以提供本机实现尚不可用的功能。网络团队没有为网站实施深色主题的计划。因此,我的应用程序看起来有点 half/half iOS 13.
暗模式支持
是否可以选择退出深色模式支持,以便我们的应用始终显示浅色模式以匹配网站主题?
我想我已经找到了解决办法。我最初是从 UIUserInterfaceStyle - Information Property List and UIUserInterfaceStyle - UIKit, but have now found it actually documented at Choosing a specific interface style for your iOS app.
拼凑起来的
在您的 info.plist
中,将 UIUserInterfaceStyle
(用户界面样式)设置为 1(UIUserInterfaceStyle.light
).
编辑:根据 dorbeetle 的回答,UIUserInterfaceStyle
更合适的设置可能是 Light
。
根据 Apple 在 "Implementing Dark Mode on iOS" 上的会话(https://developer.apple.com/videos/play/wwdc2019/214/ 从 31:13 开始),可以将 overrideUserInterfaceStyle
设置为 UIUserInterfaceStyleLight
或 UIUserInterfaceStyleDark
在任何视图控制器或视图上,将在 traitCollection
中用于任何子视图或视图控制器。
正如 SeanR 已经提到的,您可以在应用的 plist 文件中将 UIUserInterfaceStyle
设置为 Light
或 Dark
以更改整个应用的设置。
首先,这里 Apple's entry 与选择退出深色模式有关。
此link的内容是为Xcode11 & iOS13:
写的
整个应用程序通过 info.plist 文件 (Xcode 12)
在您的 info.plist 文件中使用以下密钥:
UIUserInterfaceStyle
并赋值Light
。
XML UIUserInterfaceStyle
作业:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Apple documentation for UIUserInterfaceStyle
通过 info.plist 构建设置中的整个应用程序 (Xcode 13)
整个应用 window 通过 window 属性
您可以针对应用的 window
变量设置 overrideUserInterfaceStyle
。这将适用于出现在 window 中的所有视图。这在 iOS 13 中可用,因此对于支持以前版本的应用程序,您必须包括可用性检查。
根据您的项目创建方式,这可能位于 AppDelegate
或 SceneDelegate
文件中。
if #available(iOS 13.0, *) {
window?.overrideUserInterfaceStyle = .light
}
单个 UIViewController 或 UIView
您可以针对 UIViewController
或 UIView
的 overrideUserInterfaceStyle
变量设置 overrideUserInterfaceStyle
。这在 iOS 13 中可用,因此对于支持以前版本的应用程序,您必须包括可用性检查。
Swift
override func viewDidLoad() {
super.viewDidLoad()
// overrideUserInterfaceStyle is available with iOS 13
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
}
For those poor souls in Objective-C
if (@available(iOS 13.0, *)) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
当针对 UIViewController
设置时,视图控制器及其子项采用定义的模式。
针对 UIView
设置时,视图及其子视图采用定义的模式。
Apple documentation for overrideUserInterfaceStyle
通过 SwiftUI View 的个人视图
您可以将 preferredColorScheme
设置为 light
或 dark
。提供的值将设置演示文稿的配色方案。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Light Only")
.preferredColorScheme(.light)
}
}
Apple documentation for preferredColorScheme
归功于 @Aron Nelson、@Raimundas Sakalauskas、@NSLeader 和 @rmaddy 通过他们的反馈改进了这个答案。
实际上,我刚刚编写了一些代码,允许您在代码中全局选择退出暗模式,而无需在应用程序中使用每个单独的 viw 控制器。通过管理 class 列表,这可能会被改进为 class 按 class 选择退出。对我来说,我想要的是让我的用户看到他们是否喜欢我应用程序的深色模式界面,如果他们不喜欢,他们可以将其关闭。这将使他们能够继续在其余应用程序中使用暗模式。
用户选择不错(咳咳,看你这个苹果,你应该是这样实现的)。
所以它的工作原理是它只是 UIViewController 的一个类别。当它加载时,它会将本机 viewDidLoad 方法替换为一个方法,该方法将检查全局标志以查看是否对所有内容禁用暗模式。
因为它是在 UIViewController 加载时触发的,所以它应该会自动启动并默认禁用深色模式。如果这不是你想要的,那么你需要早点到达那里并设置标志,否则只需设置默认标志。
我还没有写任何东西来响应用户打开或关闭标志。所以这基本上是示例代码。如果我们希望用户与之交互,所有的视图控制器都需要重新加载。我不知道该怎么做,但可能发送一些通知就可以解决问题。所以现在,这个用于黑暗模式的全局 on/off 只会在应用程序启动或重新启动时起作用。
现在,仅仅尝试在大型应用程序的每个 MFING viewController 中关闭暗模式是不够的。如果您使用的是颜色资产,那么您就完全没有骨气了。 10 多年来,我们已经将不可变对象理解为不可变。您从颜色资产目录中获得的颜色说它们是 UI 颜色,但它们是动态(可变)颜色,并且会随着系统从暗模式变为亮模式而在您下方发生变化。这应该是一个功能。但是当然没有主开关可以让这些东西停止进行这种改变(据我所知,也许有人可以改进这个)。
所以解决方案分为两部分:
public UIViewController 上的一个类别,它提供了一些实用和方便的方法...例如,我认为苹果没有考虑过事实上,我们中的一些人将网络代码混入我们的应用程序中。因此,我们有需要根据深色或浅色模式切换的样式表。因此,您要么需要构建某种动态样式表对象(这会很好),要么只询问当前状态是什么(不好但很容易)。
此类别在加载时将替换 UIViewController class 的 viewDidLoad 方法并拦截调用。我不知道这是否违反了应用商店规则。如果是这样,可能还有其他解决方法,但您可以将其视为概念证明。例如,您可以创建所有主要视图控制器类型的一个子 class 并使您自己的所有视图控制器都继承自这些类型,然后您可以使用 DarkMode 类别想法并调用它以强制退出所有你的视图控制器。它更丑陋,但不会违反任何规则。我更喜欢使用运行时,因为这就是运行时的用途。所以在我的版本中你只需要添加类别,你在类别上设置一个全局变量来决定你是否想要它阻止黑暗模式,它就会这样做。
如前所述,您还没有摆脱困境,另一个问题是 UIColor 基本上可以为所欲为。因此,即使您的视图控制器阻止了暗模式 UIColor 也不知道您在哪里或如何使用它,所以无法适应。因此,您可以正确获取它,但它会在将来的某个时候恢复到您身上。也许很快也许以后。因此,解决方法是使用 CGColor 将其分配两次并将其转换为静态颜色。这意味着,如果您的用户返回并在您的设置页面上 re-enables 黑暗模式(这里的想法是让这项工作起作用,以便用户可以控制您的应用程序,而不是系统的其余部分),所有这些静态颜色需要更换。到目前为止,这留给其他人解决。最简单的方法是默认你选择退出黑暗模式,除以零使应用程序崩溃,因为你不能退出它并告诉用户重新启动它。这可能也违反了应用商店指南,但这是一个想法。
UIColor 类别不需要公开,它只需调用 colorNamed: ... 如果你没有告诉 DarkMode ViewController class 阻止暗模式,它将按预期完美运行。尝试制作一些优雅的东西而不是标准的苹果意大利面条代码,这意味着如果你想以编程方式选择退出黑暗模式或切换它,你将不得不修改你的大部分应用程序。现在我不知道是否有更好的方法以编程方式将 Info.plist 更改为 tun 根据需要关闭深色模式。就我的理解而言,这是一个编译时特性,之后你就完蛋了。
这是您需要的代码。应该直接使用一种方法来设置 UI 样式或在代码中设置默认值。您可以出于任何目的自由使用、修改、做任何您想做的事情,并且不提供任何保证,我不知道它是否会通过应用程序商店。非常欢迎改进。
公平警告我不使用 ARC 或任何其他手持方法。
////// H file
#import <UIKit/UIKit.h>
@interface UIViewController(DarkMode)
// if you want to globally opt out of dark mode you call these before any view controllers load
// at the moment they will only take effect for future loaded view controllers, rather than currently
// loaded view controllers
// we are doing it like this so you don't have to fill your code with @availables() when you include this
typedef enum {
QOverrideUserInterfaceStyleUnspecified,
QOverrideUserInterfaceStyleLight,
QOverrideUserInterfaceStyleDark,
} QOverrideUserInterfaceStyle;
// the opposite condition is light interface mode
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)override;
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
// utility methods
// this will tell you if any particular view controller is operating in dark mode
- (BOOL)isUsingDarkInterfaceStyle;
// this will tell you if any particular view controller is operating in light mode mode
- (BOOL)isUsingLightInterfaceStyle;
// this is called automatically during all view controller loads to enforce a single style
- (void)tryToOverrideUserInterfaceStyle;
@end
////// M file
//
// QDarkMode.m
#import "UIViewController+DarkMode.h"
#import "q-runtime.h"
@implementation UIViewController(DarkMode)
typedef void (*void_method_imp_t) (id self, SEL cmd);
static void_method_imp_t _nativeViewDidLoad = NULL;
// we can't @available here because we're not in a method context
static long _override = -1;
+ (void)load;
{
#define DEFAULT_UI_STYLE UIUserInterfaceStyleLight
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
_override = DEFAULT_UI_STYLE;
/*
This doesn't work...
NSUserDefaults *d = NSUserDefaults.standardUserDefaults;
[d setObject:@"Light" forKey:@"UIUserInterfaceStyle"];
id uiStyle = [d objectForKey:@"UIUserInterfaceStyle"];
NSLog(@"%@",uiStyle);
*/
if (!_nativeViewDidLoad) {
Class targetClass = UIViewController.class;
SEL targetSelector = @selector(viewDidLoad);
SEL replacementSelector = @selector(_overrideModeViewDidLoad);
_nativeViewDidLoad = (void_method_imp_t)QMethodImplementationForSEL(targetClass,targetSelector);
QInstanceMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// we do it like this because it's not going to be set often, and it will be tested often
// so we can cache the value that we want to hand to the OS
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)style;
{
if (@available(iOS 13,*)){
switch(style) {
case QOverrideUserInterfaceStyleLight: {
_override = UIUserInterfaceStyleLight;
} break;
case QOverrideUserInterfaceStyleDark: {
_override = UIUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH - more modes can go here*/
case QOverrideUserInterfaceStyleUnspecified: {
_override = UIUserInterfaceStyleUnspecified;
} break;
}
}
}
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
{
if (@available(iOS 13,*)){
switch(_override) {
case UIUserInterfaceStyleLight: {
return QOverrideUserInterfaceStyleLight;
} break;
case UIUserInterfaceStyleDark: {
return QOverrideUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH */
case UIUserInterfaceStyleUnspecified: {
return QOverrideUserInterfaceStyleUnspecified;
} break;
}
} else {
// we can't override anything below iOS 12
return QOverrideUserInterfaceStyleUnspecified;
}
}
- (BOOL)isUsingDarkInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark){
return YES;
}
}
return NO;
}
- (BOOL)isUsingLightInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
return YES;
}
// if it's unspecified we should probably assume light mode, esp. iOS 12
}
return YES;
}
- (void)tryToOverrideUserInterfaceStyle;
{
// we have to check again or the compile will bitch
if (@available(iOS 13,*)) {
[self setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)_override];
}
}
// this method will be called via the viewDidLoad chain as we will patch it into the
// UIViewController class
- (void)_overrideModeViewDidLoad;
{
if (_nativeViewDidLoad) {
_nativeViewDidLoad(self,@selector(viewDidLoad));
}
[self tryToOverrideUserInterfaceStyle];
}
@end
// keep this in the same file, hidden away as it needs to switch on the global ... yeah global variables, I know, but viewDidLoad and colorNamed: are going to get called a ton and already it's adding some inefficiency to an already inefficient system ... you can change if you want to make it a class variable.
// this is necessary because UIColor will also check the current trait collection when using asset catalogs
// so we need to repair colorNamed: and possibly other methods
@interface UIColor(DarkMode)
@end
@implementation UIColor (DarkMode)
typedef UIColor *(*color_method_imp_t) (id self, SEL cmd, NSString *name);
static color_method_imp_t _nativeColorNamed = NULL;
+ (void)load;
{
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
if (!_nativeColorNamed) {
// we need to call it once to force the color assets to load
Class targetClass = UIColor.class;
SEL targetSelector = @selector(colorNamed:);
SEL replacementSelector = @selector(_overrideColorNamed:);
_nativeColorNamed = (color_method_imp_t)QClassMethodImplementationForSEL(targetClass,targetSelector);
QClassMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// basically the colors you get
// out of colorNamed: are dynamic colors... as the system traits change underneath you, the UIColor object you
// have will also change since we can't force override the system traits all we can do is force the UIColor
// that's requested to be allocated out of the trait collection, and then stripped of the dynamic info
// unfortunately that means that all colors throughout the app will be static and that is either a bug or
// a good thing since they won't respond to the system going in and out of dark mode
+ (UIColor *)_overrideColorNamed:(NSString *)string;
{
UIColor *value = nil;
if (@available(iOS 13,*)) {
value = _nativeColorNamed(self,@selector(colorNamed:),string);
if (_override != UIUserInterfaceStyleUnspecified) {
// the value we have is a dynamic color... we need to resolve against a chosen trait collection
UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_override];
value = [value resolvedColorWithTraitCollection:tc];
}
} else {
// this is unreachable code since the method won't get patched in below iOS 13, so this
// is left blank on purpose
}
return value;
}
@end
有一组实用函数可用于进行方法交换。单独的文件。这是标准的东西,你可以在任何地方找到类似的代码。
// q-runtime.h
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <stdatomic.h>
// returns the method implementation for the selector
extern IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector);
// as above but gets class method
extern IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector);
extern BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
extern BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
// q-runtime.m
static BOOL
_QMethodOverride(Class targetClass, SEL targetSelector, Method original, Method replacement)
{
BOOL flag = NO;
IMP imp = method_getImplementation(replacement);
// we need something to work with
if (replacement) {
// if something was sitting on the SEL already
if (original) {
flag = method_setImplementation(original, imp) ? YES : NO;
// if we're swapping, use this
//method_exchangeImplementations(om, rm);
} else {
// not sure this works with class methods...
// if it's not there we want to add it
flag = YES;
const char *types = method_getTypeEncoding(replacement);
class_addMethod(targetClass,targetSelector,imp,types);
XLog_FB(red,black,@"Not sure this works...");
}
}
return flag;
}
BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getInstanceMethod(targetClass,targetSelector);
Method rm = class_getInstanceMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getClassMethod(targetClass,targetSelector);
Method rm = class_getClassMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getInstanceMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getClassMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
我正在从几个文件中复制和粘贴它,因为 q-runtime.h 是我的可重用库,而这只是其中的一部分。如果无法编译,请告诉我。
如果您想退出整个应用程序,上述答案有效。如果您正在处理具有 UI 的库,并且您没有足够的时间编辑 .plist,您也可以通过代码来完成。
如果您针对 iOS 13 SDK 进行编译,您可以简单地使用以下代码:
Swift:
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .light
}
Obj-C:
if (@available(iOS 13.0, *)) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
HOWEVER,如果您希望您的代码也针对 iOS 12 SDK 进行编译(现在仍然是最新稳定的 SDK),你应该求助于使用选择器。带有选择器的代码:
Swift(XCode 将显示此代码的警告,但这是目前唯一的方法,因为 属性 在 SDK 12 中不存在,因此不会编译):
if #available(iOS 13.0, *) {
if self.responds(to: Selector("overrideUserInterfaceStyle")) {
self.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
Obj-C:
if (@available(iOS 13.0, *)) {
if ([self respondsToSelector:NSSelectorFromString(@"overrideUserInterfaceStyle")]) {
[self setValue:@(UIUserInterfaceStyleLight) forKey:@"overrideUserInterfaceStyle"];
}
}
如果您将 UIUserInterfaceStyle
密钥添加到 plist 文件,Apple 可能会拒绝发布版本,如下所述:
无论如何,明确地告诉 each ViewController self.overrideUserInterfaceStyle = .light
很烦人。但是你可以为你的根 window
对象使用这段代码:
if #available(iOS 13.0, *) {
if window.responds(to: Selector(("overrideUserInterfaceStyle"))) {
window.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
请注意,您不能在 application(application: didFinishLaunchingWithOptions:)
中执行此操作,因为此选择器在早期阶段不会响应 true
。但是你可以稍后再做。如果您在应用程序中使用自定义 AppPresenter
或 AppRouter
class 而不是在 AppDelegate 中自动启动 UI,这将非常简单。
除了其他回复,根据我的理解,你只需要在针对iOS 13 SDK(使用XCode 11)进行编译时准备暗模式。
The system assumes that apps linked against the iOS 13 or later SDK
support both light and dark appearances. In iOS, you specify the
specific appearance you want by assigning a specific interface style
to your window, view, or view controller. You can also disable support
for Dark Mode entirely using an Info.plist key.
最新更新-
如果您使用 Xcode 10.x,则 iOS 13.x 的默认 UIUserInterfaceStyle
为 light
。当 运行 在 iOS 13 设备上时,它将仅在 Light 模式下工作。
无需在 Info.plist 文件中显式添加 UIUserInterfaceStyle
键,添加它会在您验证应用程序时出错,提示:
Invalid Info.plist Key. The key 'UIUserInterfaceStyle' in the Payload/AppName.appInfo.plist file is not valid.
使用Xcode 11.x时只在Info.plist文件中添加UIUserInterfaceStyle
键。
对于整个应用程序:(在 info.plist
文件中):
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Window(通常是整个应用程序):
window!.overrideUserInterfaceStyle = .light
您可以从 SceneDelegate
得到 window
UIViewController:
viewController.overrideUserInterfaceStyle = .light
你可以任意设置viewController
,甚至在viewController里面也可以self
UIView:
view.overrideUserInterfaceStyle = .light
你可以任意设置view
,甚至在视图里面[=44=]self
如果您支持更早的 iOS 版本,您可能需要使用 if #available(iOS 13.0, *) { ,,, }
。
SwiftUI 视图:
.preferredColorScheme(.light) <- This Modifier
或
.environment(\.colorScheme, .light) <- This Modifier
如果您没有使用 Xcode 11 或更高版本(即 iOS 13 或更高版本的 SDK),您的应用不会自动选择支持深色模式。因此,无需选择退出深色模式。
如果您使用的是 Xcode 11 或更高版本,系统已自动为您的应用启用深色模式。根据您的喜好,有两种禁用暗模式的方法。您可以完全禁用它或为任何特定的 window、视图或视图控制器禁用它。
为您的应用完全禁用深色模式
您可以通过在应用程序的 Info.plist 文件中包含值为 Light
的 UIUserInterfaceStyle
键来禁用深色模式。
这会忽略用户的偏好并始终为您的应用应用浅色外观。
为 Window、视图或视图控制器禁用深色模式
您可以通过设置适当的 window、视图或视图控制器的 overrideUserInterfaceStyle
属性 强制您的界面始终以浅色或深色样式显示。
查看控制器:
override func viewDidLoad() {
super.viewDidLoad()
/* view controller’s views and child view controllers
always adopt a light interface style. */
overrideUserInterfaceStyle = .light
}
观看次数:
// The view and all of its subviews always adopt light style.
youView.overrideUserInterfaceStyle = .light
Window:
/* Everything in the window adopts the style,
including the root view controller and all presentation controllers that
display content in that window.*/
window.overrideUserInterfaceStyle = .light
Note: Apple strongly encourages to support dark mode in your app. So,
you can only disable dark mode temporarily.
在此处阅读更多内容:Choosing a Specific Interface Style for Your iOS App
是的,您可以通过在 viewDidLoad 中添加以下代码来跳过:
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
我的应用目前不支持深色模式,而是使用浅色应用栏颜色。通过将以下键添加到我的 Info.plist
:
,我能够将状态栏内容强制为深色文本和图标
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDarkContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
在此处查找其他可能的值:https://developer.apple.com/documentation/uikit/uistatusbarstyle
Flutter 用户
不要忘记像这样在 Flutter 应用栏上设置应用栏亮度属性:
AppBar(
backgroundColor: Colors.grey[100],
brightness: Brightness.light, // <---------
title: const Text('Hi there'),
),
********** Xcode 11 岁及以上的最简单方法 ***********
将此添加到 info.plist 之前 </dict></plist>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
我会使用此解决方案,因为 window 属性 可能会在应用程序生命周期中更改。所以分配 "overrideUserInterfaceStyle = .light" 需要重复。 UIWindow.appearance() 使我们能够设置将用于新创建的 UIWindow 对象的默认值。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13.0, *) {
UIWindow.appearance().overrideUserInterfaceStyle = .light
}
return true
}
}
这里有一些提示和技巧,您可以在您的应用中使用它们来支持或绕过深色模式。
第一个提示:覆盖 ViewController 样式
您可以通过
覆盖UIViewController的界面风格
1: overrideUserInterfaceStyle = .dark //For dark mode
2: overrideUserInterfaceStyle = .light //For light mode
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
overrideUserInterfaceStyle = .light
}
}
第二个提示:在 info.plist
中添加一个键
只需添加一个新密钥即可
UIUserInterfaceStyle
在您的应用中 info.plist 并将其值设置为浅色或深色。这会将应用程序默认样式覆盖为您提供的值。
您不必在每个 viewController 中添加 overrideUserInterfaceStyle = .light 这一行,只需在 info.plist 中添加一行即可。
只需在 info.plist
文件中添加以下键即可:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
您可以在 Xcode 11:
的整个应用程序中关闭 暗模式
- 去Info.plist
像
一样添加波纹管
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Info.plist 将如下所示...
只需在 info.plist 文件中添加这些行:
<key>UIUserInterfaceStyle</key>
<string>light</string>
这将强制应用仅在轻模式下 运行。
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
} else {
// Fallback on earlier versions
}
Objective-c版本
if (@available(iOS 13.0, *)) {
_window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
import UIKit
extension UIViewController {
override open func awakeFromNib() {
super.awakeFromNib()
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
}
}
您可以这样做:将这个新键 UIUserInterfaceStyle 添加到 Info.plist 并将其值设置为 Light。并检查警报控制器以灯光模式出现。
UIUserInterfaceStyle
光
如果您通过将键 UIUserInterfaceStyle 添加到 Info.plist 文件并将其值设置为 Light 或 Dark 来强制在整个应用程序中使用 light/dark 模式,而不考虑用户的设置。
这个问题有很多答案,而不是在 info.plist
中使用它,您可以像这样在 AppDelegate
中设置它:
#if compiler(>=5.1)
if #available(iOS 13.0, *) {
self.window?.overrideUserInterfaceStyle = .light
}
#endif
测试 Xcode 11.3,iOS 13.3
Swift 5
两种将暗模式切换为亮模式的方法:
1- info.plist
<key>UIUserInterfaceStyle</key>
<string>Light</string>
2- Programmatically or Runtime
@IBAction private func switchToDark(_ sender: UIButton){
UIApplication.shared.windows.forEach { window in
//here you can switch between the dark and light
window.overrideUserInterfaceStyle = .dark
}
}
Xcode 12 和 iOS 14 更新。我尝试了 opt-out 黑暗模式之前的选项,但 info.plist 文件中的这句话对我不起作用:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
现更名为:
<key>Appearance</key>
<string>Light</string>
此设置将阻止完整应用中的所有深色模式。
已编辑:
修正了错别字,感谢@sarah
在Xcode12中,您可以更改添加为“外观”。这将工作!
将此添加到 info.plist
<key>UIUserInterfaceStyle</key>
<string>Light</string>
iOS 14.3 和 Xcode 12.3 更新
在 info.plist 文件中添加 外观 作为 Light.
<key>Appearance</key>
<string>Light</string>
是的..您可以在 iOS 项目中添加以下设置。
在 info.plist 文件中将 UIUserInterfaceStyle 添加到 Light。
如果您的项目是在 IONIC 中..您可以在配置文件中添加以下设置
<platform name="ios">
<edit-config file="*-Info.plist" mode="merge" target="UIUserInterfaceStyle">
<string>Light</string>
</edit-config>
</platform>
使用这些设置,设备黑暗模式不会影响您的应用。
在 ViewController.swift 文件中添加 overrideUserInterfaceStyle = .light
或在 info.plist 文件中将外观更改为“光”
我的应用程序的很大一部分由 Web 视图组成,以提供本机实现尚不可用的功能。网络团队没有为网站实施深色主题的计划。因此,我的应用程序看起来有点 half/half iOS 13.
暗模式支持是否可以选择退出深色模式支持,以便我们的应用始终显示浅色模式以匹配网站主题?
我想我已经找到了解决办法。我最初是从 UIUserInterfaceStyle - Information Property List and UIUserInterfaceStyle - UIKit, but have now found it actually documented at Choosing a specific interface style for your iOS app.
拼凑起来的在您的 info.plist
中,将 UIUserInterfaceStyle
(用户界面样式)设置为 1(UIUserInterfaceStyle.light
).
编辑:根据 dorbeetle 的回答,UIUserInterfaceStyle
更合适的设置可能是 Light
。
根据 Apple 在 "Implementing Dark Mode on iOS" 上的会话(https://developer.apple.com/videos/play/wwdc2019/214/ 从 31:13 开始),可以将 overrideUserInterfaceStyle
设置为 UIUserInterfaceStyleLight
或 UIUserInterfaceStyleDark
在任何视图控制器或视图上,将在 traitCollection
中用于任何子视图或视图控制器。
正如 SeanR 已经提到的,您可以在应用的 plist 文件中将 UIUserInterfaceStyle
设置为 Light
或 Dark
以更改整个应用的设置。
首先,这里 Apple's entry 与选择退出深色模式有关。 此link的内容是为Xcode11 & iOS13:
写的整个应用程序通过 info.plist 文件 (Xcode 12)
在您的 info.plist 文件中使用以下密钥:
UIUserInterfaceStyle
并赋值Light
。
XML UIUserInterfaceStyle
作业:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Apple documentation for UIUserInterfaceStyle
通过 info.plist 构建设置中的整个应用程序 (Xcode 13)
整个应用 window 通过 window 属性
您可以针对应用的 window
变量设置 overrideUserInterfaceStyle
。这将适用于出现在 window 中的所有视图。这在 iOS 13 中可用,因此对于支持以前版本的应用程序,您必须包括可用性检查。
根据您的项目创建方式,这可能位于 AppDelegate
或 SceneDelegate
文件中。
if #available(iOS 13.0, *) {
window?.overrideUserInterfaceStyle = .light
}
单个 UIViewController 或 UIView
您可以针对 UIViewController
或 UIView
的 overrideUserInterfaceStyle
变量设置 overrideUserInterfaceStyle
。这在 iOS 13 中可用,因此对于支持以前版本的应用程序,您必须包括可用性检查。
Swift
override func viewDidLoad() {
super.viewDidLoad()
// overrideUserInterfaceStyle is available with iOS 13
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
}
For those poor souls in Objective-C
if (@available(iOS 13.0, *)) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
当针对 UIViewController
设置时,视图控制器及其子项采用定义的模式。
针对 UIView
设置时,视图及其子视图采用定义的模式。
Apple documentation for overrideUserInterfaceStyle
通过 SwiftUI View 的个人视图
您可以将 preferredColorScheme
设置为 light
或 dark
。提供的值将设置演示文稿的配色方案。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Light Only")
.preferredColorScheme(.light)
}
}
Apple documentation for preferredColorScheme
归功于 @Aron Nelson、@Raimundas Sakalauskas、@NSLeader 和 @rmaddy 通过他们的反馈改进了这个答案。
实际上,我刚刚编写了一些代码,允许您在代码中全局选择退出暗模式,而无需在应用程序中使用每个单独的 viw 控制器。通过管理 class 列表,这可能会被改进为 class 按 class 选择退出。对我来说,我想要的是让我的用户看到他们是否喜欢我应用程序的深色模式界面,如果他们不喜欢,他们可以将其关闭。这将使他们能够继续在其余应用程序中使用暗模式。
用户选择不错(咳咳,看你这个苹果,你应该是这样实现的)。
所以它的工作原理是它只是 UIViewController 的一个类别。当它加载时,它会将本机 viewDidLoad 方法替换为一个方法,该方法将检查全局标志以查看是否对所有内容禁用暗模式。
因为它是在 UIViewController 加载时触发的,所以它应该会自动启动并默认禁用深色模式。如果这不是你想要的,那么你需要早点到达那里并设置标志,否则只需设置默认标志。
我还没有写任何东西来响应用户打开或关闭标志。所以这基本上是示例代码。如果我们希望用户与之交互,所有的视图控制器都需要重新加载。我不知道该怎么做,但可能发送一些通知就可以解决问题。所以现在,这个用于黑暗模式的全局 on/off 只会在应用程序启动或重新启动时起作用。
现在,仅仅尝试在大型应用程序的每个 MFING viewController 中关闭暗模式是不够的。如果您使用的是颜色资产,那么您就完全没有骨气了。 10 多年来,我们已经将不可变对象理解为不可变。您从颜色资产目录中获得的颜色说它们是 UI 颜色,但它们是动态(可变)颜色,并且会随着系统从暗模式变为亮模式而在您下方发生变化。这应该是一个功能。但是当然没有主开关可以让这些东西停止进行这种改变(据我所知,也许有人可以改进这个)。
所以解决方案分为两部分:
public UIViewController 上的一个类别,它提供了一些实用和方便的方法...例如,我认为苹果没有考虑过事实上,我们中的一些人将网络代码混入我们的应用程序中。因此,我们有需要根据深色或浅色模式切换的样式表。因此,您要么需要构建某种动态样式表对象(这会很好),要么只询问当前状态是什么(不好但很容易)。
此类别在加载时将替换 UIViewController class 的 viewDidLoad 方法并拦截调用。我不知道这是否违反了应用商店规则。如果是这样,可能还有其他解决方法,但您可以将其视为概念证明。例如,您可以创建所有主要视图控制器类型的一个子 class 并使您自己的所有视图控制器都继承自这些类型,然后您可以使用 DarkMode 类别想法并调用它以强制退出所有你的视图控制器。它更丑陋,但不会违反任何规则。我更喜欢使用运行时,因为这就是运行时的用途。所以在我的版本中你只需要添加类别,你在类别上设置一个全局变量来决定你是否想要它阻止黑暗模式,它就会这样做。
如前所述,您还没有摆脱困境,另一个问题是 UIColor 基本上可以为所欲为。因此,即使您的视图控制器阻止了暗模式 UIColor 也不知道您在哪里或如何使用它,所以无法适应。因此,您可以正确获取它,但它会在将来的某个时候恢复到您身上。也许很快也许以后。因此,解决方法是使用 CGColor 将其分配两次并将其转换为静态颜色。这意味着,如果您的用户返回并在您的设置页面上 re-enables 黑暗模式(这里的想法是让这项工作起作用,以便用户可以控制您的应用程序,而不是系统的其余部分),所有这些静态颜色需要更换。到目前为止,这留给其他人解决。最简单的方法是默认你选择退出黑暗模式,除以零使应用程序崩溃,因为你不能退出它并告诉用户重新启动它。这可能也违反了应用商店指南,但这是一个想法。
UIColor 类别不需要公开,它只需调用 colorNamed: ... 如果你没有告诉 DarkMode ViewController class 阻止暗模式,它将按预期完美运行。尝试制作一些优雅的东西而不是标准的苹果意大利面条代码,这意味着如果你想以编程方式选择退出黑暗模式或切换它,你将不得不修改你的大部分应用程序。现在我不知道是否有更好的方法以编程方式将 Info.plist 更改为 tun 根据需要关闭深色模式。就我的理解而言,这是一个编译时特性,之后你就完蛋了。
这是您需要的代码。应该直接使用一种方法来设置 UI 样式或在代码中设置默认值。您可以出于任何目的自由使用、修改、做任何您想做的事情,并且不提供任何保证,我不知道它是否会通过应用程序商店。非常欢迎改进。
公平警告我不使用 ARC 或任何其他手持方法。
////// H file
#import <UIKit/UIKit.h>
@interface UIViewController(DarkMode)
// if you want to globally opt out of dark mode you call these before any view controllers load
// at the moment they will only take effect for future loaded view controllers, rather than currently
// loaded view controllers
// we are doing it like this so you don't have to fill your code with @availables() when you include this
typedef enum {
QOverrideUserInterfaceStyleUnspecified,
QOverrideUserInterfaceStyleLight,
QOverrideUserInterfaceStyleDark,
} QOverrideUserInterfaceStyle;
// the opposite condition is light interface mode
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)override;
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
// utility methods
// this will tell you if any particular view controller is operating in dark mode
- (BOOL)isUsingDarkInterfaceStyle;
// this will tell you if any particular view controller is operating in light mode mode
- (BOOL)isUsingLightInterfaceStyle;
// this is called automatically during all view controller loads to enforce a single style
- (void)tryToOverrideUserInterfaceStyle;
@end
////// M file
//
// QDarkMode.m
#import "UIViewController+DarkMode.h"
#import "q-runtime.h"
@implementation UIViewController(DarkMode)
typedef void (*void_method_imp_t) (id self, SEL cmd);
static void_method_imp_t _nativeViewDidLoad = NULL;
// we can't @available here because we're not in a method context
static long _override = -1;
+ (void)load;
{
#define DEFAULT_UI_STYLE UIUserInterfaceStyleLight
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
_override = DEFAULT_UI_STYLE;
/*
This doesn't work...
NSUserDefaults *d = NSUserDefaults.standardUserDefaults;
[d setObject:@"Light" forKey:@"UIUserInterfaceStyle"];
id uiStyle = [d objectForKey:@"UIUserInterfaceStyle"];
NSLog(@"%@",uiStyle);
*/
if (!_nativeViewDidLoad) {
Class targetClass = UIViewController.class;
SEL targetSelector = @selector(viewDidLoad);
SEL replacementSelector = @selector(_overrideModeViewDidLoad);
_nativeViewDidLoad = (void_method_imp_t)QMethodImplementationForSEL(targetClass,targetSelector);
QInstanceMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// we do it like this because it's not going to be set often, and it will be tested often
// so we can cache the value that we want to hand to the OS
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)style;
{
if (@available(iOS 13,*)){
switch(style) {
case QOverrideUserInterfaceStyleLight: {
_override = UIUserInterfaceStyleLight;
} break;
case QOverrideUserInterfaceStyleDark: {
_override = UIUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH - more modes can go here*/
case QOverrideUserInterfaceStyleUnspecified: {
_override = UIUserInterfaceStyleUnspecified;
} break;
}
}
}
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
{
if (@available(iOS 13,*)){
switch(_override) {
case UIUserInterfaceStyleLight: {
return QOverrideUserInterfaceStyleLight;
} break;
case UIUserInterfaceStyleDark: {
return QOverrideUserInterfaceStyleDark;
} break;
default:
/* FALLTHROUGH */
case UIUserInterfaceStyleUnspecified: {
return QOverrideUserInterfaceStyleUnspecified;
} break;
}
} else {
// we can't override anything below iOS 12
return QOverrideUserInterfaceStyleUnspecified;
}
}
- (BOOL)isUsingDarkInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark){
return YES;
}
}
return NO;
}
- (BOOL)isUsingLightInterfaceStyle;
{
if (@available(iOS 13,*)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
return YES;
}
// if it's unspecified we should probably assume light mode, esp. iOS 12
}
return YES;
}
- (void)tryToOverrideUserInterfaceStyle;
{
// we have to check again or the compile will bitch
if (@available(iOS 13,*)) {
[self setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)_override];
}
}
// this method will be called via the viewDidLoad chain as we will patch it into the
// UIViewController class
- (void)_overrideModeViewDidLoad;
{
if (_nativeViewDidLoad) {
_nativeViewDidLoad(self,@selector(viewDidLoad));
}
[self tryToOverrideUserInterfaceStyle];
}
@end
// keep this in the same file, hidden away as it needs to switch on the global ... yeah global variables, I know, but viewDidLoad and colorNamed: are going to get called a ton and already it's adding some inefficiency to an already inefficient system ... you can change if you want to make it a class variable.
// this is necessary because UIColor will also check the current trait collection when using asset catalogs
// so we need to repair colorNamed: and possibly other methods
@interface UIColor(DarkMode)
@end
@implementation UIColor (DarkMode)
typedef UIColor *(*color_method_imp_t) (id self, SEL cmd, NSString *name);
static color_method_imp_t _nativeColorNamed = NULL;
+ (void)load;
{
// we won't mess around with anything that is not iOS 13 dark mode capable
if (@available(iOS 13,*)) {
// default setting is to override into light style
if (!_nativeColorNamed) {
// we need to call it once to force the color assets to load
Class targetClass = UIColor.class;
SEL targetSelector = @selector(colorNamed:);
SEL replacementSelector = @selector(_overrideColorNamed:);
_nativeColorNamed = (color_method_imp_t)QClassMethodImplementationForSEL(targetClass,targetSelector);
QClassMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
}
}
}
// basically the colors you get
// out of colorNamed: are dynamic colors... as the system traits change underneath you, the UIColor object you
// have will also change since we can't force override the system traits all we can do is force the UIColor
// that's requested to be allocated out of the trait collection, and then stripped of the dynamic info
// unfortunately that means that all colors throughout the app will be static and that is either a bug or
// a good thing since they won't respond to the system going in and out of dark mode
+ (UIColor *)_overrideColorNamed:(NSString *)string;
{
UIColor *value = nil;
if (@available(iOS 13,*)) {
value = _nativeColorNamed(self,@selector(colorNamed:),string);
if (_override != UIUserInterfaceStyleUnspecified) {
// the value we have is a dynamic color... we need to resolve against a chosen trait collection
UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_override];
value = [value resolvedColorWithTraitCollection:tc];
}
} else {
// this is unreachable code since the method won't get patched in below iOS 13, so this
// is left blank on purpose
}
return value;
}
@end
有一组实用函数可用于进行方法交换。单独的文件。这是标准的东西,你可以在任何地方找到类似的代码。
// q-runtime.h
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <stdatomic.h>
// returns the method implementation for the selector
extern IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector);
// as above but gets class method
extern IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector);
extern BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
extern BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector);
// q-runtime.m
static BOOL
_QMethodOverride(Class targetClass, SEL targetSelector, Method original, Method replacement)
{
BOOL flag = NO;
IMP imp = method_getImplementation(replacement);
// we need something to work with
if (replacement) {
// if something was sitting on the SEL already
if (original) {
flag = method_setImplementation(original, imp) ? YES : NO;
// if we're swapping, use this
//method_exchangeImplementations(om, rm);
} else {
// not sure this works with class methods...
// if it's not there we want to add it
flag = YES;
const char *types = method_getTypeEncoding(replacement);
class_addMethod(targetClass,targetSelector,imp,types);
XLog_FB(red,black,@"Not sure this works...");
}
}
return flag;
}
BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getInstanceMethod(targetClass,targetSelector);
Method rm = class_getInstanceMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
Class replacementClass, SEL replacementSelector)
{
BOOL flag = NO;
if (targetClass && replacementClass) {
Method om = class_getClassMethod(targetClass,targetSelector);
Method rm = class_getClassMethod(replacementClass,replacementSelector);
flag = _QMethodOverride(targetClass,targetSelector,om,rm);
}
return flag;
}
IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getInstanceMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector)
{
Method method = class_getClassMethod(aClass,aSelector);
if (method) {
return method_getImplementation(method);
} else {
return NULL;
}
}
我正在从几个文件中复制和粘贴它,因为 q-runtime.h 是我的可重用库,而这只是其中的一部分。如果无法编译,请告诉我。
如果您想退出整个应用程序,上述答案有效。如果您正在处理具有 UI 的库,并且您没有足够的时间编辑 .plist,您也可以通过代码来完成。
如果您针对 iOS 13 SDK 进行编译,您可以简单地使用以下代码:
Swift:
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .light
}
Obj-C:
if (@available(iOS 13.0, *)) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
HOWEVER,如果您希望您的代码也针对 iOS 12 SDK 进行编译(现在仍然是最新稳定的 SDK),你应该求助于使用选择器。带有选择器的代码:
Swift(XCode 将显示此代码的警告,但这是目前唯一的方法,因为 属性 在 SDK 12 中不存在,因此不会编译):
if #available(iOS 13.0, *) {
if self.responds(to: Selector("overrideUserInterfaceStyle")) {
self.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
Obj-C:
if (@available(iOS 13.0, *)) {
if ([self respondsToSelector:NSSelectorFromString(@"overrideUserInterfaceStyle")]) {
[self setValue:@(UIUserInterfaceStyleLight) forKey:@"overrideUserInterfaceStyle"];
}
}
如果您将 UIUserInterfaceStyle
密钥添加到 plist 文件,Apple 可能会拒绝发布版本,如下所述:self.overrideUserInterfaceStyle = .light
很烦人。但是你可以为你的根 window
对象使用这段代码:
if #available(iOS 13.0, *) {
if window.responds(to: Selector(("overrideUserInterfaceStyle"))) {
window.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
}
}
请注意,您不能在 application(application: didFinishLaunchingWithOptions:)
中执行此操作,因为此选择器在早期阶段不会响应 true
。但是你可以稍后再做。如果您在应用程序中使用自定义 AppPresenter
或 AppRouter
class 而不是在 AppDelegate 中自动启动 UI,这将非常简单。
除了其他回复,根据我的理解,你只需要在针对iOS 13 SDK(使用XCode 11)进行编译时准备暗模式。
The system assumes that apps linked against the iOS 13 or later SDK support both light and dark appearances. In iOS, you specify the specific appearance you want by assigning a specific interface style to your window, view, or view controller. You can also disable support for Dark Mode entirely using an Info.plist key.
最新更新-
如果您使用 Xcode 10.x,则 iOS 13.x 的默认 UIUserInterfaceStyle
为 light
。当 运行 在 iOS 13 设备上时,它将仅在 Light 模式下工作。
无需在 Info.plist 文件中显式添加 UIUserInterfaceStyle
键,添加它会在您验证应用程序时出错,提示:
Invalid Info.plist Key. The key 'UIUserInterfaceStyle' in the Payload/AppName.appInfo.plist file is not valid.
使用Xcode 11.x时只在Info.plist文件中添加UIUserInterfaceStyle
键。
对于整个应用程序:(在 info.plist
文件中):
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Window(通常是整个应用程序):
window!.overrideUserInterfaceStyle = .light
您可以从 SceneDelegate
UIViewController:
viewController.overrideUserInterfaceStyle = .light
你可以任意设置viewController
,甚至在viewController里面也可以self
UIView:
view.overrideUserInterfaceStyle = .light
你可以任意设置view
,甚至在视图里面[=44=]self
如果您支持更早的 iOS 版本,您可能需要使用 if #available(iOS 13.0, *) { ,,, }
。
SwiftUI 视图:
.preferredColorScheme(.light) <- This Modifier
或
.environment(\.colorScheme, .light) <- This Modifier
如果您没有使用 Xcode 11 或更高版本(即 iOS 13 或更高版本的 SDK),您的应用不会自动选择支持深色模式。因此,无需选择退出深色模式。
如果您使用的是 Xcode 11 或更高版本,系统已自动为您的应用启用深色模式。根据您的喜好,有两种禁用暗模式的方法。您可以完全禁用它或为任何特定的 window、视图或视图控制器禁用它。
为您的应用完全禁用深色模式
您可以通过在应用程序的 Info.plist 文件中包含值为 Light
的 UIUserInterfaceStyle
键来禁用深色模式。
这会忽略用户的偏好并始终为您的应用应用浅色外观。
为 Window、视图或视图控制器禁用深色模式
您可以通过设置适当的 window、视图或视图控制器的 overrideUserInterfaceStyle
属性 强制您的界面始终以浅色或深色样式显示。
查看控制器:
override func viewDidLoad() {
super.viewDidLoad()
/* view controller’s views and child view controllers
always adopt a light interface style. */
overrideUserInterfaceStyle = .light
}
观看次数:
// The view and all of its subviews always adopt light style.
youView.overrideUserInterfaceStyle = .light
Window:
/* Everything in the window adopts the style,
including the root view controller and all presentation controllers that
display content in that window.*/
window.overrideUserInterfaceStyle = .light
Note: Apple strongly encourages to support dark mode in your app. So, you can only disable dark mode temporarily.
在此处阅读更多内容:Choosing a Specific Interface Style for Your iOS App
是的,您可以通过在 viewDidLoad 中添加以下代码来跳过:
if #available(iOS 13.0, *) {
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
}
我的应用目前不支持深色模式,而是使用浅色应用栏颜色。通过将以下键添加到我的 Info.plist
:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDarkContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
在此处查找其他可能的值:https://developer.apple.com/documentation/uikit/uistatusbarstyle
Flutter 用户
不要忘记像这样在 Flutter 应用栏上设置应用栏亮度属性:
AppBar(
backgroundColor: Colors.grey[100],
brightness: Brightness.light, // <---------
title: const Text('Hi there'),
),
********** Xcode 11 岁及以上的最简单方法 ***********
将此添加到 info.plist 之前 </dict></plist>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
我会使用此解决方案,因为 window 属性 可能会在应用程序生命周期中更改。所以分配 "overrideUserInterfaceStyle = .light" 需要重复。 UIWindow.appearance() 使我们能够设置将用于新创建的 UIWindow 对象的默认值。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13.0, *) {
UIWindow.appearance().overrideUserInterfaceStyle = .light
}
return true
}
}
这里有一些提示和技巧,您可以在您的应用中使用它们来支持或绕过深色模式。
第一个提示:覆盖 ViewController 样式
您可以通过
覆盖UIViewController的界面风格1: overrideUserInterfaceStyle = .dark //For dark mode
2: overrideUserInterfaceStyle = .light //For light mode
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
overrideUserInterfaceStyle = .light
}
}
第二个提示:在 info.plist
中添加一个键只需添加一个新密钥即可
UIUserInterfaceStyle
在您的应用中 info.plist 并将其值设置为浅色或深色。这会将应用程序默认样式覆盖为您提供的值。 您不必在每个 viewController 中添加 overrideUserInterfaceStyle = .light 这一行,只需在 info.plist 中添加一行即可。
只需在 info.plist
文件中添加以下键即可:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
您可以在 Xcode 11:
的整个应用程序中关闭 暗模式- 去Info.plist
像
一样添加波纹管<key>UIUserInterfaceStyle</key> <string>Light</string>
Info.plist 将如下所示...
只需在 info.plist 文件中添加这些行:
<key>UIUserInterfaceStyle</key>
<string>light</string>
这将强制应用仅在轻模式下 运行。
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
} else {
// Fallback on earlier versions
}
Objective-c版本
if (@available(iOS 13.0, *)) {
_window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
import UIKit
extension UIViewController {
override open func awakeFromNib() {
super.awakeFromNib()
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
}
}
您可以这样做:将这个新键 UIUserInterfaceStyle 添加到 Info.plist 并将其值设置为 Light。并检查警报控制器以灯光模式出现。
UIUserInterfaceStyle 光 如果您通过将键 UIUserInterfaceStyle 添加到 Info.plist 文件并将其值设置为 Light 或 Dark 来强制在整个应用程序中使用 light/dark 模式,而不考虑用户的设置。
这个问题有很多答案,而不是在 info.plist
中使用它,您可以像这样在 AppDelegate
中设置它:
#if compiler(>=5.1)
if #available(iOS 13.0, *) {
self.window?.overrideUserInterfaceStyle = .light
}
#endif
测试 Xcode 11.3,iOS 13.3
Swift 5
两种将暗模式切换为亮模式的方法:
1- info.plist
<key>UIUserInterfaceStyle</key>
<string>Light</string>
2- Programmatically or Runtime
@IBAction private func switchToDark(_ sender: UIButton){
UIApplication.shared.windows.forEach { window in
//here you can switch between the dark and light
window.overrideUserInterfaceStyle = .dark
}
}
Xcode 12 和 iOS 14 更新。我尝试了 opt-out 黑暗模式之前的选项,但 info.plist 文件中的这句话对我不起作用:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
现更名为:
<key>Appearance</key>
<string>Light</string>
此设置将阻止完整应用中的所有深色模式。
已编辑:
修正了错别字,感谢@sarah
在Xcode12中,您可以更改添加为“外观”。这将工作!
将此添加到 info.plist
<key>UIUserInterfaceStyle</key>
<string>Light</string>
iOS 14.3 和 Xcode 12.3 更新
在 info.plist 文件中添加 外观 作为 Light.
<key>Appearance</key>
<string>Light</string>
是的..您可以在 iOS 项目中添加以下设置。
在 info.plist 文件中将 UIUserInterfaceStyle 添加到 Light。
如果您的项目是在 IONIC 中..您可以在配置文件中添加以下设置
<platform name="ios">
<edit-config file="*-Info.plist" mode="merge" target="UIUserInterfaceStyle">
<string>Light</string>
</edit-config>
</platform>
使用这些设置,设备黑暗模式不会影响您的应用。
在 ViewController.swift 文件中添加 overrideUserInterfaceStyle = .light
或在 info.plist 文件中将外观更改为“光”