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

如何将SwiftUI Color存入UserDefaults并通过@AppStorage读写?

问题描述

我开发的App适配macOS 12和iOS 15,使用自定义SwiftUI Color(例如Color(red: 1.47, green: 1.9, blue: 2.3).opacity(1)),运行正常。现在需要将部分Color存入UserDefaults,通过UserDefaults.standard和@AppStorage读写,但直接存入会触发运行时错误,代码如下:

static let infoListRowReadBGColor = Color(red: 2.55, green: 1.71, blue: 1.07).opacity(1)
static let infoListRowUnReadBGColor = Color(red: 2.55, green: 2.12, blue: 1.38).opacity(1)

var defaults = UserDefaults.standard

defaults.setValue(InAppDefaults.infoListRowReadBGColor, forKey: "infoListRowReadBGColor")
defaults.setValue(InAppDefaults.infoListRowUnReadBGColor, forKey: "infoListRowUnReadBGColor")

我尝试过扩展方法,但无法配合@AppStorage使用,当前用Xcode13/14开发,请问该如何修改实现需求?

解决方案

SwiftUI的Color并非PropertyList兼容类型,无法直接存入UserDefaults。要实现存储并配合@AppStorage,需要将Color转换为可序列化的格式,再通过RawRepresentable协议让Color支持@AppStorage。

步骤1:实现Color的RawRepresentable扩展

通过将Color的RGBA值转换为[Double]数组(作为RawValue),实现编码和解码:

import SwiftUI

extension Color: RawRepresentable {
    public init?(rawValue: [Double]) {
        guard rawValue.count == 4 else { return nil }
        self.init(red: rawValue[0], green: rawValue[1], blue: rawValue[2], opacity: rawValue[3])
    }

    public var rawValue: [Double] {
        #if os(iOS) || os(tvOS) || os(watchOS)
        let platformColor = UIColor(self)
        #elseif os(macOS)
        let platformColor = NSColor(self)
        #endif
        
        var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
        platformColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return [Double(red), Double(green), Double(blue), Double(alpha)]
    }
}

步骤2:使用@AppStorage存储Color

现在可以直接用@AppStorage定义存储的Color属性:

@AppStorage("infoListRowReadBGColor") var infoListRowReadBGColor: Color = Color(red: 2.55, green: 1.71, blue: 1.07).opacity(1)
@AppStorage("infoListRowUnReadBGColor") var infoListRowUnReadBGColor: Color = Color(red: 2.55, green: 2.12, blue: 1.38).opacity(1)

步骤3:手动操作UserDefaults(可选)

如果需要直接通过UserDefaults.standard读写,可利用rawValue转换:

// 存储
let readColorRaw = infoListRowReadBGColor.rawValue
UserDefaults.standard.set(readColorRaw, forKey: "infoListRowReadBGColor")

// 读取
if let rawValue = UserDefaults.standard.array(forKey: "infoListRowReadBGColor") as? [Double],
   let savedColor = Color(rawValue: rawValue) {
    // 使用savedColor
}

注意事项

  • 你示例中的red:2.55超出了SwiftUI Color的标准取值范围(0-1),框架会自动修正,但建议提前将工具输出的0-255数值转换为0-1范围(例如255/255=1),避免潜在问题。
  • Xcode13/14对RawRepresentable类型的@AppStorage支持正常,无需额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:06:31