如何将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
相关产品推荐
相关产品推荐

