目的
SwiftUIで背景のColor
を永続化したいことがありましたが、iOS14+のコードが多く、iOS13に対応した動くコードが見つからなかったので、メモしておきます。
コード
Extensionで汎用化する必要がなかったので、メソッドで定義しています。また、UserDefaultsの実装はインターネット上に例が多いので、ここでは詳細は省略します。
func colorHandler(_ color: Color){
var persistenceData = UserDefault_Keys()
if #available(iOS 14.0, *) {
if let components = color.cgColor?.components {
persistenceData.advBgColorR = Double(components[0])
persistenceData.advBgColorG = Double(components[1])
persistenceData.advBgColorB = Double(components[2])
persistenceData.advBgColorA = Double(components[3])
}
} else {
let description = color.description
let elements: [String] = description.components(separatedBy: " ")
var r: Double = 0.0, g: Double = 0.0, b: Double = 0.0, a: Double = 0.0
if color == Color.white {
r = 1.0
g = 1.0
b = 1.0
a = 1.0
} else if color == Color.black {
r = 0.0
g = 0.0
b = 0.0
a = 1.0
} else {
r = Double(elements[1]) ?? 0.0
g = Double(elements[2]) ?? 0.0
b = Double(elements[3]) ?? 0.0
a = Double(elements[4]) ?? 0.0
}
persistenceData.advBgColorR = r
persistenceData.advBgColorG = g
persistenceData.advBgColorB = b
persistenceData.advBgColorA = a
}
}
【ポイント1】iOS14+ではcgColor
が使えるが、iOS13では使えない(将来的にiOS13がアプリのサポート対象外となれば、実装が簡潔になる)
【ポイント2】color.description
は、システムカラー(Color.whiteなど)の場合は、[UIExtendedSRGBColorSpace 1 1]などと書式が異なりRGB値を取得できないので、条件分岐が必要(ここの例では、メソッドの引数になるシステムカラーが白か黒だけの想定)。なお、システムカラー以外の場合は、UIExtendedSRGBColorSpace 0.839216 0.521569 0.690196 1
のような値になる
let persistenceData = UserDefault_Keys()
let color = Color(red: persistenceData.advBgColorR, green: persistenceData.advBgColorG, blue: persistenceData.advBgColorB, opacity: persistenceData.advBgColorA)
import SwiftUI
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
struct UserDefault_Keys {
@UserDefault(key: "Adv_bgColor_R", defaultValue: 0.0)
var advBgColorR: Double
@UserDefault(key: "Adv_bgColor_G", defaultValue: 0.0)
var advBgColorG: Double
@UserDefault(key: "Adv_bgColor_B", defaultValue: 0.0)
var advBgColorB: Double
@UserDefault(key: "Adv_bgColor_A", defaultValue: 0.0)
var advBgColorA: Double
}
参考リンク
Handling Colors in SwiftUI
How can I change a SwiftUI Color to UIColor? *コメントにある通り、正常に動きませんが参考にはなる
[SwiftUI] SwiftUI の Color を UserDefaults に保存する *ライブラリ使用、iOS14+
UserDefaultsをProperty Wrapperでカッコよく使う
Save/Get UIColor from UserDefaults