I am trying to make individually moveable objects. I am able to successfully do it for one object but once I place it into an array, the objects are not able to move anymore.
Model:
class SocialStore: ObservableObject {
@Published var socials : [Social]
init(socials: [Social]){
self.socials = socials
}
}
class Social : ObservableObject{
var id: Int
var imageName: String
var companyName: String
@Published var pos: CGPoint
init(id: Int, imageName: String, companyName: String, pos: CGPoint) {
self.id = id
self.imageName = imageName
self.companyName = companyName
self.pos = pos
}
var dragGesture : some Gesture {
DragGesture()
.onChanged { value in
self.pos = value.location
print(self.pos)
}
}
}
Multiple image (images not following drag):
struct ContentView : View {
@ObservedObject var socialObject: SocialStore = SocialStore(socials: testData)
@ObservedObject var images: Social = testData[2]
var body: some View {
VStack {
ForEach(socialObject.socials, id: \.id) { social in
Image(social.imageName)
.position(social.pos)
.gesture(social.dragGesture)
}
}
}
}
Single image (image follow gesture):
struct ContentView : View {
@ObservedObject var socialObject: SocialStore = SocialStore(socials: testData)
@ObservedObject var images: Social = testData[2]
var body: some View {
VStack {
Image(images.imageName)
.position(images.pos)
.gesture(images.dragGesture)
}
}
}
I expect the individual items to be able to move freely . I see that the coordinates are updating but the position of each image is not.
Using includes() Method: If array contains an object/element can be determined by using includes() method. This method returns true if the array contains the object/element else return false. Example: html.
assign() method to convert an array of objects to a single object. This merges each object into a single resultant object. The Object. assign() method also merges the properties of one or more objects into a single object.
You can use the includes() method in JavaScript to check if an item exists in an array. You can also use it to check if a substring exists within a string. It returns true if the item is found in the array/string and false if the item doesn't exist.
Arrays are Objects Arrays are a special type of objects. The typeof operator in JavaScript returns "object" for arrays.
First, a disclaimer: The code below is not meant as a copy-and-paste solution. Its only goal is to help you understand the challenge. There may be more efficient ways of resolving it, so take your time to think of your implementation once you understand the problem.
Why the view does not update?: The @Publisher
in SocialStore
will only emit an update when the array changes. Since nothing is being added or removed from the array, nothing will happen. Additionally, because the array elements are objects (and not values), when they do change their position, the array remains unaltered, because the reference to the objects remains the same. Remember: Classes create objects, Structs create values.
We need a way of making the store, to emit a change when something in its element changes. In the example below, your store will subscribe to each of its elements bindings. Now, all published updates from your items, will be relayed to your store publisher, and you will obtain the desired result.
import SwiftUI
import Combine
class SocialStore: ObservableObject {
@Published var socials : [Social]
var cancellables = [AnyCancellable]()
init(socials: [Social]){
self.socials = socials
self.socials.forEach({
let c = $0.objectWillChange.sink(receiveValue: { self.objectWillChange.send() })
// Important: You have to keep the returned value allocated,
// otherwise the sink subscription gets cancelled
self.cancellables.append(c)
})
}
}
class Social : ObservableObject{
var id: Int
var imageName: String
var companyName: String
@Published var pos: CGPoint
init(id: Int, imageName: String, companyName: String, pos: CGPoint) {
self.id = id
self.imageName = imageName
self.companyName = companyName
self.pos = pos
}
var dragGesture : some Gesture {
DragGesture()
.onChanged { value in
self.pos = value.location
print(self.pos)
}
}
}
struct ContentView : View {
@ObservedObject var socialObject: SocialStore = SocialStore(socials: testData)
var body: some View {
VStack {
ForEach(socialObject.socials, id: \.id) { social in
Image(social.imageName)
.position(social.pos)
.gesture(social.dragGesture)
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With