简体   繁体   English

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

[英]Swift Swiftui - Saving Color to UserDefaults and use it from @AppStorage

In my App for MacOS and iOS I use colors created from here: https://uiwjs.github.io/ui-color/ and then fe Works fine. In my App for MacOS and iOS I use colors created from here: https://uiwjs.github.io/ui-color/ and then fe Works fine.

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

However for some colors I want them saved in the userDefaults and read/write by UserDefaults.standard methodes and read/write by @AppStorage.但是,对于某些 colors,我希望它们保存在 userDefaults 中,并通过 UserDefaults.standard 方法读取/写入,并通过 @AppStorage 读取/写入。

I did try to use, but this gives me runtime errors.我确实尝试过使用,但这给了我运行时错误。

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")
        

What do I need to change to get this working, read and write, using UserDefaults.default and @AppStore?使用 UserDefaults.default 和 @AppStore,我需要进行哪些更改才能使其正常工作、读取和写入? I did try the extension methode from a posting around here, but I guess I do something very wrong, because it doesn't work with @AppStorage.我确实尝试了此处发布的扩展方法,但我想我做错了什么,因为它不适用于@AppStorage。

Using XCode 13 and 14 for dev result for MacOS 12 and iOS 15.使用 XCode 13 和 14 作为 MacOS 12 和 iOS 15 的开发结果。

you can try converting color into data and store the data instead.您可以尝试将颜色转换为数据并存储数据。

here's a uikit version extending UIColor you can use it for SwiftUI's Color too这是扩展 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)
    }
}

you can persist the color using the encode function and once you retrieve the data, you can pass it on the class func to get the color您可以使用编码 function 保持颜色,一旦您检索数据,您可以将其传递给 class 函数以获取颜色

You can't by default store Color() in UserDefaults, but you can use @AppStorage and NSKeyedArchiver to achieve this result.默认情况下,您不能将 Color() 存储在 UserDefaults 中,但您可以使用 @AppStorage 和 NSKeyedArchiver 来实现此结果。 The full example and documentation is provided from this article . 本文提供了完整的示例和文档。

Create an extension:创建一个扩展:

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 ""
            
        }
        
    }

}

And use it as such:并像这样使用它:

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

The answer that EJZ gives has put me on the right track. EJZ给出的答案让我走上了正轨。 I've tried other methods as well, but the EJZ method I was able to use for both iOS and OSX with a little tweaking.我也尝试过其他方法,但我可以对 iOS 和 OSX 使用 EJZ 方法,只需稍作调整。 Not wanting to edit his answer to keep that clear, I copied his part and my tweak into this answer.不想编辑他的答案以保持清晰,我将他的部分和我的调整复制到了这个答案中。

I hope this helps others too.我希望这对其他人也有帮助。 Thank you EJZ and others as well as the people for reading this too.感谢 EJZ 和其他人以及阅读本文的人们。

=== ===

To split the os's I use an import distinction in the top/Import area of the file of the scene area part.为了拆分操作系统,我在场景区域部分的文件的顶部/导入区域中使用了导入区别。

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

Here's the file I tweaked with the OS distinction这是我用操作系统区别调整的文件

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 ""
        }
    }
}

Both works well with the ( using the code of EJZ ) the @AppStorage SwiftUI views and both systems.两者都适用于(使用 EJZ 的代码)@AppStorage SwiftUI 视图和两个系统。

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

HOWEVER: why is the size of the saved rawdata so big?但是:为什么保存的原始数据的大小如此之大?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM