iCo*_*eak 1 list swift swiftui combine
I tried creating a list of custom classes in SwiftUI, but keep having problems with the UI updates. I made my class conform to BindableObject
and it calls the didChange.send()
function correctly when a property changes, but the change doesn't seem to get passed through to the array, as the view does not update, when I change a property of my custom class in the array.
Here is a basic example of what I mean:
class Media: BindableObject, Identifiable {
typealias PublisherType = PassthroughSubject<Void, Never>
var didChange = PublisherType()
var id: Int {
didSet {
didChange.send()
}
}
var name: String {
didSet {
print("Name changed from \(oldValue) to \(self.name)")
didChange.send()
}
}
init(id: Int, name: String) {
self.id = id
self.name = name
}
}
struct ContentView : View {
@State private var media = [
Media(id: 0, name: "Name 0"),
Media(id: 1, name: "Name 1"),
Media(id: 2, name: "Name 2"),
Media(id: 3, name: "Name 3"),
]
var body: some View {
VStack {
List(media) { media in
Text(media.name)
}
HStack {
Button(action: {
self.media.first!.name = "Name \(Int.random(in: 100...199))"
}) {
Text("Change")
}
Button(action: {
self.media.append(Media(id: 4, name: "Name 4"))
}) {
Text("Add")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
When pressing the "Change" button, it just changes the name of the first media object in the array, which does not result in a re-rendering of the view. When I press the "Add" button, he adds an object to the array, therefore re-rendering the UI and also displaying the changed name of the first object (from pressing "Change").
Now my question is, if there is a way to link the publisher of Media
to the publisher of Array<Media>
, so that when the Media
Publisher fires, the Array<Media>
Publisher fires too and therefore causes the view to re-render.
When I move the Text(media.name)
in a separate view (which holds the media as a @State
property, it works as intended, as the subview itself request the re-render.
但是,假设我不想使用自定义视图,而只是使用简单Text
视图,是否有任何方法可以实现此目的?
您正在混合两种不同的东西。@State用于视图内部的任何内容。@BindableObject是用于在视图外部保存某些内容(即,数据模型)。定义@BindableObject时,不使用@State引用它,而是使用@ObjectBinding引用它。
我不知道是什么情况,但是如果您打算使用@State,则实现应该是这样的:
struct Media {
var id: Int
var name: String
init(id: Int, name: String) {
self.id = id
self.name = name
}
}
struct ContentView : View {
@State var media = [
Media(id: 0, name: "Name 0"),
Media(id: 1, name: "Name 1"),
Media(id: 2, name: "Name 2"),
Media(id: 3, name: "Name 3"),
]
var body: some View {
VStack {
List(media.identified(by: \.id)) { media in
Text(media.name)
}
HStack {
Button(action: {
self.media[0].name = "Name \(Int.random(in: 100...199))"
}) {
Text("Change")
}
Button(action: {
self.media.append(Media(id: 4, name: "Name 4"))
}) {
Text("Add")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您通常将@State用于视图的某些内部状态,同时也用于原型制作。您对Media对象的意图是什么?
要使用@ObjectBinding实现它:
假设您要在SceneDelegate中实例化CustomView,则需要将其传递给库:
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let library = MediaLibrary(store: [Media(id: 0, name: "Name 0"),
Media(id: 1, name: "Name 1"),
Media(id: 2, name: "Name 2"),
Media(id: 3, name: "Name 3")])
window.rootViewController = UIHostingController(rootView: ContentView(library: library))
self.window = window
window.makeKeyAndVisible()
}
Run Code Online (Sandbox Code Playgroud)
并执行:
struct Media {
let id: Int
var name: String
init(id: Int, name: String) {
self.id = id
self.name = name
}
}
class MediaLibrary: BindableObject {
typealias PublisherType = PassthroughSubject<Void, Never>
var didChange = PublisherType()
var store: [Media] {
didSet {
didChange.send()
}
}
init(store: [Media]) {
self.store = store
}
}
struct ContentView : View {
@ObjectBinding var library: MediaLibrary
var body: some View {
VStack {
List(self.library.store.identified(by: \.id)) { media in
Text(media.name)
}
HStack {
Button(action: {
self.library.store[0].name = "Name \(Int.random(in: 100...199))"
}) {
Text("Change")
}
Button(action: {
self.library.store.append(Media(id: 4, name: "Name 4"))
}) {
Text("Add")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1070 次 |
最近记录: |