如何检查 iOS/iPadOS 中是不是启用了深色模式?

Posted

技术标签:

【中文标题】如何检查 iOS/iPadOS 中是不是启用了深色模式?【英文标题】:How can I check whether dark mode is enabled in iOS/iPadOS?如何检查 iOS/iPadOS 中是否启用了深色模式? 【发布时间】:2019-10-19 12:03:00 【问题描述】:

ios/iPadOS 13 开始,可以使用深色用户界面样式,类似于 macOS Mojave 中引入的深色模式。如何检查用户是否启用了系统范围的暗模式?

【问题讨论】:

这个用户界面实际上是从 tvOS 10 和 iOS 12 开始可用的——在 iOS 12 上,它只是在辅助功能选项中作为“反转颜色”提供 Aaron Brager 的评论有些不准确 - 是的,您可以“反转颜色”,但它与打开暗模式有很大不同。它可能会给您的应用程序仍然可用的错误印象。例如:如果您无意中将系统颜色与您自己的颜色混合在一起,那么 invert 会反转所有这些颜色。但是,在暗模式下,系统颜色会改变,而你的不会。因此,就像 Touchgram v1.1.0 一样,您最终可以在非常淡蓝色的背景上获得近乎白色的文本。 App Store 评论不支持这个! 这里是 To check the current state,这是给 Observing for live changes of the state 的。两个答案都涵盖了 UIKit/AppKit/SwiftUI 等。 【参考方案1】:

对于iOS 13,您可以使用此属性检查当前样式是否为深色模式:

if #available(iOS 13.0, *) 
    if UITraitCollection.current.userInterfaceStyle == .dark 
        print("Dark mode")
    
    else 
        print("Light mode")
    

【讨论】:

如果您想签入 AppDelegate,这很好,因为它没有像 UIViewController 这样的 traitCollection 变量 谢谢!最后确实是 AppDelegate 问题的正确答案:) 这对禁用的暗模式没有反应。如果你使用window?.overrideUserInterfaceStyle = .light,那么UITraitCollection.current.userInterfaceStyle 可以返回.dark 这在我的情况下不起作用。使我的 iOS 应用程序支持 Mac。我的 mac mini 当前外观是暗的,在 appdelegate 文件中我有时会变亮,有时会变暗模式,而不是每次都进入暗模式。请帮帮我。【参考方案2】:

您应该检查UITraitCollectionuserInterfaceStyle 变量,与tvOS 和macOS 上相同。

switch traitCollection.userInterfaceStyle 
case .light: //light mode
case .dark: //dark mode
case .unspecified: //the user interface style is not specified

您应该使用UIView/UIViewControllertraitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)函数来检测界面环境的变化(包括用户界面风格的变化)。

来自Apple Developer Documentation:

iOS界面环境变化时系统调用该方法。根据您的应用程序的需要,在视图控制器和视图中实现此方法,以响应此类更改。例如,当 iPhone 从纵向旋转到横向时,您可能会调整视图控制器的子视图的布局。该方法的默认实现为空。

系统默认 UI 元素(例如 UITabBarUISearchBar)会自动适应新的用户界面样式。

【讨论】:

除了traitCollectionDidChange(_:),您还可以检查UIViewlayoutSubviews()draw(_:)updateConstraints()tintColorDidChange()UIViewController中的变化的updateViewConstraints()viewWillLayoutSubviews()viewDidLayoutSubviews()。每次用户界面样式发生变化时,都会调用所有这些方法。 这将为您提供当前视图的用户界面样式。如果您为该特定视图覆盖了它,它不会告诉您系统的样式。【参考方案3】:

正如 daveextreme 所提到的,当您使用 overrideUserInterfaceStyle 属性时,检查当前视图用户界面样式并不总是返回系统样式。在这种情况下,最好使用以下代码:

switch UIScreen.main.traitCollection.userInterfaceStyle 
case .light: //light mode
case .dark: //dark mode
case .unspecified: //the user interface style is not specified

【讨论】:

这个答案最适合检查非 UIViewController 类中的主题。【参考方案4】:

在objective-c中你想做的:

if( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark )

        //is dark
else

    //is light


【讨论】:

【参考方案5】:

对于 Swift:

if #available(iOS 12.0, *) 
  switch UIScreen.main.traitCollection.userInterfaceStyle 
    case .dark: // put your dark mode code here
    case .light: 
    case .unspecified: 
  

对于目标 C:

if (@available(iOS 12.0, *)) 
        switch (UIScreen.mainScreen.traitCollection.userInterfaceStyle) 
            case UIUserInterfaceStyleDark:
                // put your dark mode code here
                break;
            case UIUserInterfaceStyleLight:
            case UIUserInterfaceStyleUnspecified:
                break;
            default:
                break;
        

欲了解更多信息,请观看此 WWDC2019 video

【讨论】:

我最终在我的 iOS 项目中将它用于 Xamarin.Forms。到目前为止最好的答案。 (消息灵通的可靠答案比 MS for Xamarin 的官方 doku 的一些博主的第 100 个副本更好。)@Pedro Trujillo 你救了我的一天。谢谢! 任何。 ios 11 版本?【参考方案6】:

SwiftUI

使用Environment 变量的\.colorScheme 键:

struct ContentView: View 
    @Environment(\.colorScheme) var colorScheme

    var body: some View 
        Text(colorScheme == .dark ? "In dark mode" : "In light mode")
    

此外,它会根据环境配色方案的变化自动更新。


UIKit

查看当前,所有符合UITraitEnvironment协议的对象,包括所有UIView子类和所有UIViewConttroller子类都可以访问当前样式:

myUIView.traitCollection.userInterfaceStyle == .dark
myUIViewController.traitCollection.userInterfaceStyle == .dark

要检测风格的实时变化,here is the full detailed answer

【讨论】:

我在我的 ContentView 中使用了这个方法来改变 Tab Bar 界面的强调色。在标签视图的末尾,我使用了 .accentColor(colorScheme == .dark ? .green : .black) 当像这样声明@Enironement 时,我得到Type annotation missing in pattern【参考方案7】:

1/ 对于 UIView/UIViewController:

self.traitCollection.userInterfaceStyle == .dark

2/ 用于静态或其他:

UITraitCollection.current.userInterfaceStyle == .dark

但是:

//Never use this! You will get wrong value in app extensions (ex. ToDay widget)
UIScreen.main.traitCollection.userInterfaceStyle == .dark //WRONG!

【讨论】:

实际上最后一个(UIScreen...)是在我的应用程序中覆盖 userInterfaceStyle 后,在设备设置中获取用户暗模式设置的唯一方法。通过这种方式,我能够实现一个“跟随 iOS 暗模式”按钮,即使我有自定义主题和选择,它也会立即更新应用程序的颜色主题。不幸的是,如果不覆盖 userInterfaceStyle,就不可能可靠地单独管理状态栏文本颜色。 请注意,这可能对某人有所帮助:如果您在 info.plist 中将 UIUserInterfaceStyle 设置为 light,则此方法将始终返回 light @LeonidSilver 非常感谢!!!删除系统主题(.unspecified)的 info.plist 中的 UIUserInterfaceStyle 项! 对我来说,使用键盘扩展程序,UITraitCollection.current.userInterfaceStyle 在扩展程序启动时返回正确的值,但在我打开和关闭明暗模式时不会改变。【参考方案8】:

目标 C

要通过控制中心检测何时启用或禁用暗模式,请使用“appDidBecomeActive”通知,该通知将在您返回应用时触发。

//----------------------------------------------------------------------------
//                          viewWillAppear
//----------------------------------------------------------------------------
- (void)viewWillAppear 
    [super viewWillAppear];

    [[NSNotificationCenter defaultCenter]addObserver:self
                                   selector:@selector(appDidBecomeActive:)
                                   name:UIApplicationDidBecomeActiveNotification
                                   object:nil];


完成后不要忘记删除它:

//------------------------------------------------------------------------------------
//                    viewWillDisappear
//------------------------------------------------------------------------------------
- (void)viewWillDisappear:(BOOL)animated

    [super viewWillDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self        
                                 name:UIApplicationDidBecomeActiveNotification 
                                 object:nil];


当黑暗模式改变时,做你需要做的事:

//----------------------------------------------------------------------------
//                          appDidBecomeActive
//----------------------------------------------------------------------------
-(void)appDidBecomeActive:(NSNotification*)note 
    if (@available(iOS 13.0, *)) 
        if( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark )
            //dark mode
        
        else 
            //not dark mode
        
    
    else 
        //fall back for older versions
    

【讨论】:

【参考方案9】:

为第 1 次写入方法创建一个类函数并在任何你想要的地方使用

func isDarkMode() -> Bool
    if #available(iOS 12.0, *) 
        if UIScreen.main.traitCollection.userInterfaceStyle == .dark 
            return true
         else 
            return false
        
     else 
       return false
    
  

【讨论】:

【参考方案10】:

以下适用于任何 iOS 版本的辅助方法:

var isDarkMode: Bool 
    guard #available(iOS 12.0, *) else 
        return false
    

    return UIScreen.main.traitCollection.userInterfaceStyle == .dark

用法:

view.backgroundColor = isDarkMode ? .black : .white

【讨论】:

欢迎来到 Stack Overflow。没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请edit您的问题并解释它如何比OP提供的更好。 @Chris。感谢您的评论,但实际上这里的每个答案都是一个代码转储......这个问题非常简单,答案也是如此。感谢您指出这一点,我会添加更多解释 这不会使纯代码答案可接受。这条评论被标记为“低质量答案”,可能是因为它纯粹是代码,或者是“迟到的回复”(我不记得是哪个),我通过审查队列发表了评论。最好突出显示您更改的内容、更改原因以及您的答案如何改进现有答案。我数了个早于你的答案。让你的脱颖而出。【参考方案11】:

检测变化的最佳点是 UIView/UIViewController 的 traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 函数。

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
    super.traitCollectionDidChange(previousTraitCollection)

    let userInterfaceStyle = traitCollection.userInterfaceStyle // Either .unspecified, .light, or .dark
    // Update your user interface based on the appearance

通过覆盖视图控制器上的 traitCollectionDidChange 来检测外观变化是微不足道的。然后,只需访问视图控制器的 traitCollection.userInterfaceStyle。

但是,重要的是要记住,可能会为其他特征更改调用 traitCollectionDidChange,例如设备旋转。您可以使用这种新方法检查当前外观是否不同:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
    super.traitCollectionDidChange(previousTraitCollection)

    let hasUserInterfaceStyleChanged = previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) // Bool
    // Update your user interface based on the appearance

【讨论】:

【参考方案12】:
var isDarkMode: Bool 
    guard #available(iOS 12.0, *) else 
        return false
    
    let window = (UIApplication.shared.delegate as? AppDelegate)?.window
    return window?.traitCollection.userInterfaceStyle == .dark

如果你没有在 AppDelegate 中使用 window,请从 SceneDelegate 调用 window

它类似于上面的大多数答案,但是当我们使用改变模式时,这会更好

window?.overrideUserInterfaceStyle = .dark

可以称为

isDarkMode ? .black : .white

【讨论】:

【参考方案13】:

你可以使用这个扩展:

import UIKit

extension UIApplication 
    @available(iOS 13.0, *)
    var userInterfaceStyle: UIUserInterfaceStyle? 
        return self.keyWindow?.traitCollection.userInterfaceStyle
    


@available(iOS 13.0, *)
    func setSystemTheme() 
        switch UIApplication.shared.userInterfaceStyle 
        case .dark?:
            currentTheme = .dark
        case .light?:
            currentTheme = .light
        default:
            break
        
    

【讨论】:

【参考方案14】:

也许有一些不错的扩展?

public extension UIViewController 
    @available(iOS 12.0, *)
    public var isDarkMode: Bool  traitCollection.userInterfaceStyle == .dark 

【讨论】:

【参考方案15】:

您可以使用此方法 Swift 5 轻松检测暗模式或亮模式

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
if traitCollection.userInterfaceStyle == .light 
    print("Light mode")
 else 
    print("Dark mode")

【讨论】:

【参考方案16】:

您可以使用以下代码检查项目中的明暗模式:

func viewDidLoad() 
    super.viewDidLoad()

    switch traitCollection.userInterfaceStyle 
        case .light, .unspecified:
            // light mode detected
        case .dark:
            // dark mode detected
    

您还可以检查界面样式的变化:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
    super.traitCollectionDidChange(previousTraitCollection)

    let userInterfaceStyle = traitCollection.userInterfaceStyle // Either .unspecified, .light, or .dark
    // Update your user interface based on the appearance

就像自 Mojave 以来在 macOS 中一样,您可以在资产目录中为明暗模式定义图像,以便自动使用这些图像:

【讨论】:

以上是关于如何检查 iOS/iPadOS 中是不是启用了深色模式?的主要内容,如果未能解决你的问题,请参考以下文章

iPad 检测用户是不是启用了暗模式,但不支持暗模式

如何在 YouTrack 中设置深色主题

如何检查 WordPress 中是不是启用了 XML-RPC

iOS/iPadOS 中的 SwiftUI + DocumentGroup:如何重命名当前打开的文档

苹果新开发工具 让iOS/iPadOS 15设备优先使用5G

新iOS/iPadOS15开发工具优先考虑5G而非WiFi