问题描述
对于我的窗口小部件,我希望用户能够选择自己选择的窗口小部件背景颜色,但是我似乎无法使其正常工作。
我正在尝试使用ColorPicker
和@AppStorage
ColorPicker("Background Color",selection: Binding(get: {
bgColor
},set: { newValue in
backgroundColor = self.updateColorInAppStorage(color: newValue)
bgColor = newValue
}))
.frame(width: 200,height: 50)
.font(.headline)
backgroundColor是一个@AppStorage
变量,用于保存RGB值
在我的Widget扩展类中,我使用此变量在@main结构中设置窗口小部件的背景色:
@main
struct MyWidget: Widget {
@AppStorage("backgroundColor",store: UserDefaults(suiteName: "group.com.MyWidget")) var backgroundColor = ""
@State private var bgColor = Color(UIColor.systemBackground)
let kind: String = "Count"
var body: some WidgetConfiguration {
IntentConfiguration(kind: kind,intent: ConfigurationIntent.self,provider: Provider()) { entry in
SubscriberCountEntryView(entry: entry)
.frame(maxWidth: .infinity,maxHeight: .infinity)
.background(bgColor)
.onAppear {
if (backgroundColor != "") {
let rgbArray = backgroundColor.components(separatedBy: ",")
if let red = Double(rgbArray[0]),let green = Double(rgbArray[1]),let blue = Double(rgbArray[2]),let alpha = Double(rgbArray[3]) {
bgColor = Color(.sRGB,red: red,green: green,blue: blue,opacity: alpha)
}
}
}
}
.configurationdisplayName("Count")
.supportedFamilies([.systemSmall,.systemMedium])
}
}
这似乎仅在将应用程序首次安装在设备上时有效。之后,无论我选择颜色多少次并更新小部件,背景颜色都不会改变。如果我再次删除并安装该应用,则颜色会更改。
关于如何正确执行此操作的任何想法?
解决方法
您正在窗口小部件而不是窗口小部件的时间轴提供程序中访问UserDefaults。您还将以不必要的复杂方式存储颜色。
这是一个简单的示例,向您展示如何将UIColor保存到UserDefaults中并在小部件中访问它。尽管您使用的是Color,但是可以从UIColor创建Color结构。但是,ColorPicker
允许您使用CGColor
或Color
创建绑定,并且CGColor
可以轻松转换为UIColor
。
ContentView
在ContentView中,我创建了一个简单的应用程序,该应用程序使用绑定有CGColor
的ColorPicker。选择颜色后,我们将其作为UIColor传递给保存功能。这使用NSKeyedArchiver
将UIColor转换为Data,可以轻松地将其保存到UserDefaults中。我使用AppStorage
存储从UIColor创建的数据。
然后我们调用WidgetCenter.shared.reloadAllTimelines()
,以确保WidgetCenter知道我们要更新小部件。
import SwiftUI
import WidgetKit
struct ContentView: View {
@AppStorage("color",store: UserDefaults(suiteName: "group.com.my.app.identifier"))
var colorData: Data = Data()
@State private var bgColor: CGColor = UIColor.systemBackground.cgColor
var body: some View {
ColorPicker("Color",selection: Binding(get: {
bgColor
},set: { newValue in
save(color: UIColor(cgColor: newValue))
bgColor = newValue
}))
}
func save(color: UIColor) {
do {
colorData = try NSKeyedArchiver.archivedData(withRootObject: color,requiringSecureCoding: false)
WidgetCenter.shared.reloadAllTimelines()
} catch let error {
print("error color key data not saved \(error.localizedDescription)")
}
}
}
MyWidget
接下来,在提供程序中,我们使用属性包装器AppStorage
访问为颜色保存的数据。我们无法在AppStorage
内部或MyWidgetEntryView
内部访问MyWidget
,因为在那儿无法使用。
在提供程序内部,我创建了一个计算属性,该属性从我们存储在AppStorage
中的颜色数据中获取UIColor。然后,创建该颜色时会将其传递给每个条目。这是对您的窗口小部件使用AppStorage
的关键,创建条目时必须传递值。
MyWidgetEntryView非常简单,它仅显示创建日期和背景颜色。
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
@AppStorage("color",store: UserDefaults(suiteName: "group.com.my.app.identifier"))
var colorData: Data = Data()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(color: color)
}
func getSnapshot(in context: Context,completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(color: color)
completion(entry)
}
func getTimeline(in context: Context,completion: @escaping (Timeline<Entry>) -> ()) {
let entry = SimpleEntry(color: color)
let timeline = Timeline(entries: [entry],policy: .atEnd)
completion(timeline)
}
var color: UIColor {
var color: UIColor?
do {
color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self,from: colorData)
} catch let error {
print("color error \(error.localizedDescription)")
}
return color ?? .systemBlue
}
}
struct SimpleEntry: TimelineEntry {
let date: Date = Date()
let color: UIColor
}
struct MyWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
ZStack {
Color(entry.color)
Text(entry.date,style: .time)
}
}
}
@main
struct MyWidget: Widget {
let kind: String = "MyWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind,provider: Provider()) { entry in
MyWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
在这里工作?