如何正确链接CADisplayLink与SwiftUI?

tnkciper  于 2023-01-16  发布在  Swift
关注(0)|答案(1)|浏览(169)

我正在创建一些动画,为了在各种设备上实现流畅性,我使用CADisplayLink,如下所示:

// DisplayLink.swift
import SwiftUI

class DisplayLink: NSObject, ObservableObject {
    @Published var frameDuration: CFTimeInterval = 0
    @Published var frameChange: Bool = false
    
    static let sharedInstance: DisplayLink = DisplayLink()
    
    func createDisplayLink() {
        let displaylink = CADisplayLink(target: self, selector: #selector(frame))
        displaylink.add(to: .current, forMode: RunLoop.Mode.default)
    }
    
    @objc func frame(displaylink: CADisplayLink) {
        frameDuration = displaylink.targetTimestamp - displaylink.timestamp
        frameChange.toggle()
    }
    
}

然后我在应用程序中初始化它一次:

// App.swift
import SwiftUI

@main
struct App: App {
    init() {
        DisplayLink.sharedInstance.createDisplayLink()
    }
    var body: some Scene {
        WindowGroup {
            CircleView()
        }
    }
}

我在整个应用程序中使用它,如下所示:

// CircleView.swift
import SwiftUI

struct CircleView: View {
    @ObservedObject var displayLink = DisplayLink.sharedInstance
    //
    var body: some View {
       // 
       .onChange(of: displayLink.frameChange) { _ in
              print(displayLink.frameDuration)
           }
    }

一切都很好,但是使用这种方法有多正确呢?也许SwiftUI已经有现成的方法了?

hmmo2u0o

hmmo2u0o1#

我喜欢你的解决方案-它工作得很好。这是一个用闭包代替@Published的替代方案。

class DisplayLink: NSObject, ObservableObject {
    
    private var displaylink: CADisplayLink?
    private var update: ((TimeInterval) -> Void)?
    
    func start(update: @escaping (TimeInterval) -> Void) {
        self.update = update
        displaylink = CADisplayLink(target: self, selector: #selector(frame))
        displaylink?.add(to: .current, forMode: .default)
    }
    
    func stop() {
        displaylink?.remove(from: .current, forMode: .default)
        update = nil
    }
    
    @objc func frame(displaylink: CADisplayLink) {
        let frameDuration = displaylink.targetTimestamp - displaylink.timestamp
        update?(frameDuration)
    }
}

在swift UI类中:

@State private var displayLink = DisplayLink()

...

displayLink.start { frameDuration in
    update(frameDuration)
}

...

displayLink.stop()

相关问题