使用 SwiftUI 中的数组更新列表中的滑块值文本

问题描述

我有一个滑块列表,但在更新显示滑块值的文本时遇到问题。

应用工作流程是这样的:

  1. 用户点按即可将新滑块添加到列表中。
  2. 一个定义滑块的对象被创建并存储在一个数组中。
  3. 将数组作为属性 (Db) 的类是 ObservableObject,并为每个新项目触发视图更新。
  4. 列表更新为新行。

到目前为止,一切都很好。每行都有一个滑块,其值存储在数组对象的属性中。但是,移动滑块后不会立即更新值文本,而是会在添加新项目时更新。请看下面的动图:

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
}

解决方法

@ObservableObject 在这样的 struct 中不起作用——它只在 SwiftUI ViewDynamicProperty 中有用。对于您的用例,由于 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 { $0.id == id } ?? Criteria(name: "")
        } set: { newValue in
            db.criteria_db = db.criteria_db.map {
                $0.id == id ? newValue : $0
            }
        }
    }
    
    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] = []
}

现在,由于模型都是值类型 (structs),View@Published 知道何时更新并且您的滑块按预期工作。

,

尝试这样的事情:

Sub Loop4Row()
Dim r As Long,Ranges As Range

Set Ranges = Application.InputBox("Select the Range",Type:=8)
    For r = Application.Min(Ranges.Column) To Application.Max(Ranges.Columns)
        MsgBox Cells(4,r)
    Next r

End Sub