Swift Swiftui - 将颜色保存到 UserDefaults 并从 @AppStorage 使用它

问题描述 投票:0回答:3

在我的 MacOS 和 iOS 应用程序中,我使用从此处创建的颜色:https://uiwjs.github.io/ui-color/ 然后 f.e.效果很好。

Color(red: 1.47, green: 1.9, blue: 2.3).opacity(1)

但是,对于某些颜色,我希望它们保存在 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")
        

我需要更改什么才能使用 UserDefaults.default 和 @AppStore 使其工作、读取和写入?我确实尝试了这里的帖子中的扩展方法,但我想我做了一些非常错误的事情,因为它不适用于@AppStorage。

使用 XCode 13 和 14 获取 MacOS 12 和 iOS 15 的开发结果。

swift swiftui colors userdefaults
3个回答
4
投票

您可以尝试将颜色转换为数据并存储数据。

这里有一个扩展 UIColor 的 uikit 版本,你也可以将它用于 SwiftUI 的颜色

import UIKit

extension UIColor {
    class func color(data: Data) -> UIColor {
        try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! UIColor
    }

    func encode() -> Data {
        try! NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
    }
}

您可以使用编码函数保留颜色,一旦检索到数据,您可以将其传递给类函数来获取颜色


3
投票

默认情况下,您无法将 Color() 存储在 UserDefaults 中,但您可以使用 @AppStorage 和 NSKeyedArchiver 来实现此结果。 本文提供了完整的示例和文档。

创建扩展:

import Foundation
import SwiftUI
import UIKit

extension Color: RawRepresentable {

    public init?(rawValue: String) {
        
        guard let data = Data(base64Encoded: rawValue) else{
            self = .black
            return
        }
        
        do{
            let color = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIColor ?? .black
            self = Color(color)
        }catch{
            self = .black
        }
        
    }

    public var rawValue: String {
        
        do{
            let data = try NSKeyedArchiver.archivedData(withRootObject: UIColor(self), requiringSecureCoding: false) as Data
            return data.base64EncodedString()
            
        }catch{
            
            return ""
            
        }
        
    }

}

并这样使用它:

@AppStorage("colorkey") var storedColor: Color = .black
    
    var body: some View {
        
        VStack{
            ColorPicker("Persisted Color Picker", selection: $storedColor, supportsOpacity: true)
            }
}

1
投票

EJZ给出的答案让我走上了正轨。我也尝试过其他方法,但 EJZ 方法只需稍加调整即可用于 iOS 和 OSX。不想编辑他的答案以保持清晰,我将他的部分和我的调整复制到这个答案中。

import Foundation
import SwiftUI
#if os(iOS)
    import UIKit
#elseif os(OSX)
    import AppKit
#endif

这是我根据操作系统差异调整的文件

extension Color: RawRepresentable {

    public init?(rawValue: String) {
        guard let data = Data(base64Encoded: rawValue) else {
            self = .gray
            return
        }
        do{
#if os(iOS)
            let color = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIColor ?? .gray
#elseif os(OSX)
            let color = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSColor ?? .gray
#endif
            self = Color(color)
        }catch{
            self = .gray
        }
    }

    public var rawValue: String {
        do{
#if os(iOS)
            let data = try NSKeyedArchiver.archivedData(withRootObject: UIColor(self), requiringSecureCoding: false) as Data
#elseif os(OSX)
            let data = try NSKeyedArchiver.archivedData(withRootObject: NSColor(self), requiringSecureCoding: false) as Data
#endif

            return data.base64EncodedString()
        }catch{
            return ""
        }
    }
}

两者都可以很好地与(使用 EJZ 代码)@AppStorage SwiftUI 视图和两个系统配合使用。

@AppStorage("key") var storedColor: Color = .gray

但是:为什么保存的原始数据的大小这么大?

© www.soinside.com 2019 - 2024. All rights reserved.