简体   繁体   中英

How to update a view during a CADisplayLink animation

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM