I'm trying to implement a simple animation using CADisplayLink
. A black square should move slowly across the screen.
But the square appears stationary because the body
of Squares
doesn't get updated when step()
increments testX and testY.
From what I can gather (I'm new to Swift), I'm using the @ObservedObject
paradigm correctly, so I don't understand why the view won't refresh.
How do I get Squares
's body
to update along with the animation?
My code is below, thanks for your help!
class MyAnimations: NSObject, ObservableObject {
@Published var testX: Double = 0
@Published var testY: Double = 0
func createDisplayLink() {
let displaylink = CADisplayLink(target: self, selector: #selector(step))
displaylink.add(to: .current, forMode: RunLoop.Mode.default)
}
@objc func step(link: CADisplayLink) {
testX += 0.5
testY += 0.5
}
}
struct Squares: View {
@ObservedObject var animation = MyAnimations()
var body: some View {
Path { path in
path.addRect(CGRect(x: self.animation.testX, y: self.animation.testY, width: 50, height: 50))
}
.fill(Color.black)
}
}
struct SomeOtherView: View {
var body: some View {
Squares()
}
}
This is because your displaylink
is created on stack, so destroyed right after quit from function. You need to make it property.
Here is modified tested code. Tested with Xcode 12 / iOS 14.
class MyAnimations: NSObject, ObservableObject {
@Published var testX: Double = 0
@Published var testY: Double = 0
private var displaylink: CADisplayLink! // << here !!
func createDisplayLink() {
if nil == displaylink {
displaylink = CADisplayLink(target: self, selector: #selector(step))
displaylink.add(to: .current, forMode: RunLoop.Mode.default)
}
}
@objc func step(link: CADisplayLink) {
testX += 0.5
testY += 0.5
}
}
struct Squares: View {
@ObservedObject var animation = MyAnimations()
var body: some View {
Path { path in
path.addRect(CGRect(x: self.animation.testX, y: self.animation.testY, width: 50, height: 50))
}
.fill(Color.black)
.onAppear {
animation.createDisplayLink()
}
}
}
From what I see all you need is a shared instance of your ObservableObject
class MyAnimations: NSObject, ObservableObject {
@Published var testX: Double = 0
@Published var testY: Double = 0
static let sharedInstance: MyAnimations = MyAnimations()//Singleton Pattern
func createDisplayLink() {
let displaylink = CADisplayLink(target: self, selector: #selector(step))
displaylink.add(to: .current, forMode: RunLoop.Mode.default)
}
@objc func step(link: CADisplayLink) {
testX += 0.5
testY += 0.5
}
}
struct Squares: View {
//@ObservedObject var animation = MyAnimations.sharedInstance//Singleton Pattern
@EnvironmentObject var animation: MyAnimations
var body: some View {
VStack{
Button("Move", action: {
animation.createDisplayLink()
})
Path { path in
path.addRect(CGRect(x: self.animation.testX, y: self.animation.testY, width: 50, height: 50))
}
.fill(Color.black)
}
}
}
struct SomeOtherView: View {
@ObservedObject var animation = MyAnimations()
//@ObservedObject var animation = MyAnimations.sharedInstance//Singleton Pattern
var body: some View {
VStack{
Button("Trigger to Create", action: {
animation.createDisplayLink()
})//Sample Trigger
Squares()
.environmentObject(animation)//Omit if using Singleton
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.