SwiftUI中如何在@AppStorage中存储Color类型值?
解决SwiftUI中@AppStorage存储Color类型的问题
@AppStorage默认仅支持存储遵循RawRepresentable协议的类型(如String、Int、Bool等),而SwiftUI的Color类型并未实现该协议,因此直接声明@AppStorage("selectedColor") var selectedColor: Color = .teal会报错。以下是两种可行的解决方法:
方案一:给Color扩展RawRepresentable协议
通过将Color转换为Data再编码成Base64字符串,实现RawRepresentable协议,让@AppStorage可以直接存储Color:
import SwiftUI import UIKit extension Color: RawRepresentable { public init?(rawValue: String) { guard let data = Data(base64Encoded: rawValue) else { self = .black return } do { let uiColor = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: data) ?? .black self = Color(uiColor) } catch { self = .black } } public var rawValue: String { do { let uiColor = UIColor(self) let data = try NSKeyedArchiver.archivedData(withRootObject: uiColor, requiringSecureCoding: false) return data.base64EncodedString() } catch { return "" } } }
完成扩展后,你就可以直接使用最初的代码:
@AppStorage("selectedColor") var selectedColor: Color = .teal
方案二:通过Hex字符串间接存储
如果不想扩展Color类型,可以通过计算属性,将Color与Hex字符串互相转换,间接存储:
import SwiftUI import UIKit // 存储Hex字符串的@AppStorage变量 @AppStorage("selectedColorHex") private var selectedColorHex: String = "#34C759" // 默认对应.teal的Hex值 // 对外暴露的Color计算属性 var selectedColor: Color { get { Color(hex: selectedColorHex) } set { selectedColorHex = newValue.toHex() } } // 给Color添加Hex转换扩展 extension Color { /// 从Hex字符串初始化Color init(hex: String) { let cleanHex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var hexValue: UInt64 = 0 Scanner(string: cleanHex).scanHexInt64(&hexValue) let a, r, g, b: UInt64 switch cleanHex.count { case 3: // 12位RGB,如#RGB (a, r, g, b) = (255, (hexValue >> 8) * 17, (hexValue >> 4 & 0xF) * 17, (hexValue & 0xF) * 17) case 6: // 24位RGB,如#RRGGBB (a, r, g, b) = (255, hexValue >> 16, hexValue >> 8 & 0xFF, hexValue & 0xFF) case 8: // 32位ARGB,如#AARRGGBB (a, r, g, b) = (hexValue >> 24, hexValue >> 16 & 0xFF, hexValue >> 8 & 0xFF, hexValue & 0xFF) default: (a, r, g, b) = (255, 0, 0, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } /// 将Color转换为Hex字符串 func toHex() -> String { let uiColor = UIColor(self) guard let components = uiColor.cgColor.components, components.count >= 3 else { return "#000000" } let r = Float(components[0]) let g = Float(components[1]) let b = Float(components[2]) let a = Float(uiColor.cgColor.alpha) if a == 1.0 { return String(format: "#%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)) } else { return String(format: "#%02lX%02lX%02lX%02lX", lroundf(a * 255), lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)) } } }
方案对比
- 方案一:使用更便捷,和原生支持的@AppStorage类型用法一致,但依赖NSKeyedArchiver/Unarchiver,需注意跨平台兼容性(如macOS、watchOS)。
- 方案二:存储的Hex字符串可读性高,跨平台表现更稳定,但需要额外处理Color与Hex的转换逻辑。
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

