【问题标题】: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 等。

标签: ios ios13 ipados ios-darkmode


【解决方案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 中一样,您可以在资产目录中为明暗模式定义图像,以便自动使用这些图像:

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-01-16
                    • 2021-11-06
                    • 2021-08-18
                    • 1970-01-01
                    • 2021-10-07
                    • 2014-10-16
                    相关资源
                    最近更新 更多