You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 如何检测应用Interface Style是否为unspecified状态

根本原因

traitCollection.userInterfaceStyle返回的是当前界面最终生效的实际外观值,按照苹果的设计逻辑,这个值永远只会是.light或.dark,不会返回.unspecified——当你设置overrideUserInterfaceStyle = .unspecified时,代表不做强制覆盖,跟随系统当前的外观设置,因此traitCollection会直接返回系统当前的浅/深色状态,自然不会出现未指定值。

你要判断的「是否为跟随系统的unspecified状态」本质是用户配置的外观规则,和traitCollection返回的实际生效值是两个完全独立的概念,不要从traitCollection里取这个配置。

可行实现方案

核心逻辑

  • 配置状态直接从overrideUserInterfaceStyle属性读取:你给window赋值的覆盖规则会保存在这个属性本身,设置为.unspecified时直接读取该属性就能拿到对应值,不需要经过traitCollection解析。
  • 新增本地持久化:APP杀进程重启后,overrideUserInterfaceStyle会重置为默认值,需要把用户选择的配置存在本地,启动时自动恢复,保证全生命周期状态一致。
  • 封装全局访问方法:给其他业务模块提供统一的调用入口,避免各处重复取window、读traitCollection的逻辑出错。

可直接复用的代码

首先定义统一的外观枚举,和你的选择cell逻辑对应:

enum Appearance: Int {
    case device = 0 // 跟随系统,对应unspecified
    case light = 1
    case dark = 2
}

修改你原有的UIApplication扩展,新增持久化和状态读取逻辑,同时兼容iOS13+多Scene场景:

extension UIApplication {
    private static let storedAppearanceKey = "com.app.customAppearance"
    
    func changeInterfaceStyle(_ mode: UIUserInterfaceStyle) {
        // 取当前激活的keyWindow,兼容单window和多Scene场景
        let targetWindow: UIWindow?
        if #available(iOS 13.0, *) {
            targetWindow = connectedScenes
                .filter { $0.activationState == .foregroundActive }
                .compactMap { $0 as? UIWindowScene }
                .flatMap { $0.windows }
                .first(where: \.isKeyWindow)
        } else {
            targetWindow = delegate?.window ?? nil
        }
        guard let keyWindow = targetWindow else { return }
        
        keyWindow.overrideUserInterfaceStyle = mode
        
        // 持久化用户选择,APP重启后不丢失
        let storeValue: Int
        switch mode {
        case .light: storeValue = Appearance.light.rawValue
        case .dark: storeValue = Appearance.dark.rawValue
        default: storeValue = Appearance.device.rawValue
        }
        UserDefaults.standard.set(storeValue, forKey: Self.storedAppearanceKey)
    }
    
    /// 全局获取当前用户配置的外观规则
    func currentConfiguredAppearance() -> Appearance {
        guard let storedValue = UserDefaults.standard.object(forKey: Self.storedAppearanceKey) as? Int,
              let appearance = Appearance(rawValue: storedValue) else {
            // 默认为跟随系统
            return .device
        }
        return appearance
    }
}

在APP启动入口恢复之前保存的配置,避免重启后配置失效:

// AppDelegate的didFinishLaunchingWithOptions方法,或SceneDelegate的willConnectTo方法中调用
let savedAppearance = UIApplication.shared.currentConfiguredAppearance()
let overrideMode: UIUserInterfaceStyle
switch savedAppearance {
case .light: overrideMode = .light
case .dark: overrideMode = .dark
case .device: overrideMode = .unspecified
}
UIApplication.shared.changeInterfaceStyle(overrideMode)

业务模块调用方式

其他逻辑需要判断是否为unspecified(跟随系统)状态时,直接调用统一方法即可:

let isFollowSystem = UIApplication.shared.currentConfiguredAppearance() == .device

如果需要获取当前界面实际显示的是浅色还是深色(比如动态适配资源),再去读traitCollection.userInterfaceStyle即可,两个接口分别对应不同的使用场景,不要混用。

注意:不要尝试通过traitCollection反推用户配置,当系统外观刚好和用户强制设置的外观一致时(比如用户强制选浅色,系统当前也刚好是浅色),反推结果会完全错误。


内容的提问来源于stack exchange,提问作者taroPancake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 02:33:26