从 SwiftUI 中的数组更新带有列表中滑块值的文本
Update text with Slider value in List from an array in SwiftUI
我有一个滑块列表,但我在更新显示滑块值的文本时遇到问题。
应用程序的工作流程是这样的:
- 用户点击以将新滑块添加到列表。
- 定义滑块的对象已创建并存储在数组中。
- 将数组作为 属性 (Db) 的 class 是一个 ObservableObject 并为每个新项目触发视图更新。
- 列表已更新为新行。
到目前为止,还不错。每行都有一个滑块,其值存储在数组对象的 属性 中。但是,值文本不会在滑块移动后立即更新,而是在添加新项目时更新。请看下面的 GIF:
The Slider doesn't update the text value when moved
如何将滑块移动绑定到文本值?我认为通过定义
@ObservedObject var slider_value: SliderVal = SliderVal()
并将该变量绑定到滑块,该值将同时更新,但事实并非如此。非常感谢您的帮助。
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var db: Db
var body: some View {
NavigationView{
List(db.criteria_db){criteria in
VStack {
HStack{
Text(criteria.name).bold()
Spacer()
Text(String(criteria.slider_value.value)) //<-- Problem here
}
Slider(value: criteria.$slider_value.value, in:0...100, step: 1)
}
}
.navigationBarTitle("Criteria")
.navigationBarItems(trailing:
Button(action: {
Criteria.count += 1
db.criteria_db.append(Criteria(name: "Criteria\(Criteria.count)"))
dump(db.criteria_db)
}, label: {
Text("Add Criteria")
})
)
}
.listStyle(InsetGroupedListStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(db: Db())
}
}
struct Criteria: Identifiable {
var id = UUID()
var name: String
@ObservedObject var slider_value: SliderVal = SliderVal()
static var count: Int = 0
init(name: String) {
self.name = name
}
}
class Db: ObservableObject {
@Published var criteria_db: [Criteria] = []
}
class SliderVal: ObservableObject {
@Published var value:Double = 50
}
尝试这样的事情:
Slider(value: criteria.$slider_value.value, in:0...100, step: 1)
.onChange(of: criteria.slider_value.value) { newVal in
DispatchQueue.main.async {
criteria.slider_value.value = newVal
}
}
@ObservableObject
不会像这样在 struct
中工作——它只在 SwiftUI View
或 DynamicProperty
中有用。对于您的用例,因为 class
是引用类型,所以 @Published
属性 无法知道 SliderVal
已更改,因此所有者 View
永远不会更新。
您可以通过将您的模型变成 struct
:
来解决这个问题
struct Criteria: Identifiable {
var id = UUID()
var name: String
var slider_value: SliderVal = SliderVal()
static var count: Int = 0
init(name: String) {
self.name = name
}
}
struct SliderVal {
var value:Double = 50
}
一旦你这样做了,问题是你没有 Binding
可以用在你的 List
中。如果您有幸使用 SwiftUI 3.0(iOS 15 或 macOS 12),您可以在列表中使用 $criteria
来绑定当前正在迭代的元素。
如果您使用的是早期版本,则需要使用索引来遍历项目,或者,我最喜欢的,创建一个绑定到项目 id
的自定义绑定.它看起来像这样:
struct ContentView: View {
@ObservedObject var db: Db = Db()
private func bindingForId(id: UUID) -> Binding<Criteria> {
.init {
db.criteria_db.first { [=11=].id == id } ?? Criteria(name: "")
} set: { newValue in
db.criteria_db = db.criteria_db.map {
[=11=].id == id ? newValue : [=11=]
}
}
}
var body: some View {
NavigationView{
List(db.criteria_db){criteria in
VStack {
HStack{
Text(criteria.name).bold()
Spacer()
Text(String(criteria.slider_value.value))
}
Slider(value: bindingForId(id: criteria.id).slider_value.value, in:0...100, step: 1)
}
}
.navigationBarTitle("Criteria")
.navigationBarItems(trailing:
Button(action: {
Criteria.count += 1
db.criteria_db.append(Criteria(name: "Criteria\(Criteria.count)"))
dump(db.criteria_db)
}, label: {
Text("Add Criteria")
})
)
}
.listStyle(InsetGroupedListStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(db: Db())
}
}
class Db: ObservableObject {
@Published var criteria_db: [Criteria] = []
}
现在,因为模型都是值类型 (struct
s),View
和 @Published
知道何时更新并且您的滑块按预期工作。
我有一个滑块列表,但我在更新显示滑块值的文本时遇到问题。
应用程序的工作流程是这样的:
- 用户点击以将新滑块添加到列表。
- 定义滑块的对象已创建并存储在数组中。
- 将数组作为 属性 (Db) 的 class 是一个 ObservableObject 并为每个新项目触发视图更新。
- 列表已更新为新行。
到目前为止,还不错。每行都有一个滑块,其值存储在数组对象的 属性 中。但是,值文本不会在滑块移动后立即更新,而是在添加新项目时更新。请看下面的 GIF:
The Slider doesn't update the text value when moved
如何将滑块移动绑定到文本值?我认为通过定义
@ObservedObject var slider_value: SliderVal = SliderVal()
并将该变量绑定到滑块,该值将同时更新,但事实并非如此。非常感谢您的帮助。
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var db: Db
var body: some View {
NavigationView{
List(db.criteria_db){criteria in
VStack {
HStack{
Text(criteria.name).bold()
Spacer()
Text(String(criteria.slider_value.value)) //<-- Problem here
}
Slider(value: criteria.$slider_value.value, in:0...100, step: 1)
}
}
.navigationBarTitle("Criteria")
.navigationBarItems(trailing:
Button(action: {
Criteria.count += 1
db.criteria_db.append(Criteria(name: "Criteria\(Criteria.count)"))
dump(db.criteria_db)
}, label: {
Text("Add Criteria")
})
)
}
.listStyle(InsetGroupedListStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(db: Db())
}
}
struct Criteria: Identifiable {
var id = UUID()
var name: String
@ObservedObject var slider_value: SliderVal = SliderVal()
static var count: Int = 0
init(name: String) {
self.name = name
}
}
class Db: ObservableObject {
@Published var criteria_db: [Criteria] = []
}
class SliderVal: ObservableObject {
@Published var value:Double = 50
}
尝试这样的事情:
Slider(value: criteria.$slider_value.value, in:0...100, step: 1)
.onChange(of: criteria.slider_value.value) { newVal in
DispatchQueue.main.async {
criteria.slider_value.value = newVal
}
}
@ObservableObject
不会像这样在 struct
中工作——它只在 SwiftUI View
或 DynamicProperty
中有用。对于您的用例,因为 class
是引用类型,所以 @Published
属性 无法知道 SliderVal
已更改,因此所有者 View
永远不会更新。
您可以通过将您的模型变成 struct
:
struct Criteria: Identifiable {
var id = UUID()
var name: String
var slider_value: SliderVal = SliderVal()
static var count: Int = 0
init(name: String) {
self.name = name
}
}
struct SliderVal {
var value:Double = 50
}
一旦你这样做了,问题是你没有 Binding
可以用在你的 List
中。如果您有幸使用 SwiftUI 3.0(iOS 15 或 macOS 12),您可以在列表中使用 $criteria
来绑定当前正在迭代的元素。
如果您使用的是早期版本,则需要使用索引来遍历项目,或者,我最喜欢的,创建一个绑定到项目 id
的自定义绑定.它看起来像这样:
struct ContentView: View {
@ObservedObject var db: Db = Db()
private func bindingForId(id: UUID) -> Binding<Criteria> {
.init {
db.criteria_db.first { [=11=].id == id } ?? Criteria(name: "")
} set: { newValue in
db.criteria_db = db.criteria_db.map {
[=11=].id == id ? newValue : [=11=]
}
}
}
var body: some View {
NavigationView{
List(db.criteria_db){criteria in
VStack {
HStack{
Text(criteria.name).bold()
Spacer()
Text(String(criteria.slider_value.value))
}
Slider(value: bindingForId(id: criteria.id).slider_value.value, in:0...100, step: 1)
}
}
.navigationBarTitle("Criteria")
.navigationBarItems(trailing:
Button(action: {
Criteria.count += 1
db.criteria_db.append(Criteria(name: "Criteria\(Criteria.count)"))
dump(db.criteria_db)
}, label: {
Text("Add Criteria")
})
)
}
.listStyle(InsetGroupedListStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(db: Db())
}
}
class Db: ObservableObject {
@Published var criteria_db: [Criteria] = []
}
现在,因为模型都是值类型 (struct
s),View
和 @Published
知道何时更新并且您的滑块按预期工作。