Skip to content

Commit

Permalink
Merge pull request #2 from noppefoxwolf/updatelink
Browse files Browse the repository at this point in the history
Use UIUpdateLink in iOS18
  • Loading branch information
noppefoxwolf authored Dec 3, 2024
2 parents 77b14b0 + 81dc799 commit 1a173a8
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 15 deletions.
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ let package = Package(
targets: [
.target(
name: "AnimatedImage",
dependencies: [
"UpdateLink"
],
resources: [.copy("Resources/PrivacyInfo.xcprivacy")]
),
.target(
name: "UpdateLink"
),
.target(
name: "AnimatedImageSwiftUI",
dependencies: [
Expand Down
42 changes: 27 additions & 15 deletions Sources/AnimatedImage/BaseClass/AnimatableCGImageView.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
public import UIKit
import UpdateLink

open class AnimatableCGImageView: CGImageView, DisplayLinkTarget {
private var displayLink: CADisplayLink? = nil
open class AnimatableCGImageView: CGImageView {
var updateLink: (any UpdateLink)!

open func startAnimating() {
stopAnimating()
displayLink = CADisplayLink(
target: DisplayLinkProxy(target: self),
selector: #selector(DisplayLinkProxy<Self>.updateContents)
public override init(frame: CGRect) {
super.init(frame: frame)
if #available(iOS 18.0, *) {
updateLink = UIUpdateLink(view: self)
} else {
updateLink = BackportUpdateLink(view: self)
}
updateLink.isEnabled = true
updateLink.preferredFrameRateRange = CAFrameRateRange(
minimum: 1,
maximum: 60
)
displayLink?.preferredFrameRateRange = CAFrameRateRange(minimum: 1, maximum: 60)
displayLink?.add(to: .main, forMode: .common)
updateLink.addAction(handler: { [unowned self] _, info in
willUpdateContents(&contents, for: info.modelTime)
})
updateLink.requiresContinuousUpdates = true
}

open func stopAnimating() {
displayLink?.invalidate()
displayLink = nil
@MainActor public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateContents(_ displayLink: CADisplayLink) {
willUpdateContents(&contents, for: displayLink.targetTimestamp)
open func startAnimating() {
updateLink.isEnabled = true
}

open func stopAnimating() {
updateLink.isEnabled = false
}

open func willUpdateContents(_ contents: inout CGImage?, for targetTimestamp: TimeInterval) {

}
}

54 changes: 54 additions & 0 deletions Sources/UpdateLink/BackportUpdateLink.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import UIKit

public final class BackportUpdateLink: UpdateLink, DisplayLinkTarget {
private var displayLink: CADisplayLink!

public init(view: UIView) {
displayLink = CADisplayLink(
target: DisplayLinkProxy(target: self),
selector: #selector(DisplayLinkProxy<Self>.updateContents)
)
}

public var isEnabled: Bool {
get { !displayLink.isPaused }
set { displayLink.isPaused = !newValue }
}

public var requiresContinuousUpdates: Bool = false {
didSet {
if requiresContinuousUpdates {
displayLink.add(to: .main, forMode: .common)
} else {
displayLink.remove(from: .main, forMode: .common)
}
}
}

public var preferredFrameRateRange: CAFrameRateRange {
get { displayLink?.preferredFrameRateRange ?? .default }
set { displayLink?.preferredFrameRateRange = newValue }
}

private var handlers: [(any UpdateLink, any UpdateInfo) -> Void] = []
public func addAction(
handler: @escaping (any UpdateLink, any UpdateInfo) -> Void
) {
handlers.append(handler)
}

func updateContents(_ displayLink: CADisplayLink) {
let info = BackportUpdateInfo(modelTime: displayLink.targetTimestamp)
handlers.forEach { action in
action(self, info)
}
}
}

final class BackportUpdateInfo: UpdateInfo {
var modelTime: TimeInterval

init(modelTime: TimeInterval) {
self.modelTime = modelTime
}
}
File renamed without changes.
15 changes: 15 additions & 0 deletions Sources/UpdateLink/UIUpdateLink+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import UIKit

@available(iOS 18.0, *)
extension UIUpdateInfo: UpdateInfo {}

@available(iOS 18.0, *)
extension UIUpdateLink: UpdateLink {
public func addAction(
handler: @escaping (any UpdateLink, any UpdateInfo) -> Void
) {
addAction { (link: UIUpdateLink, info: UIUpdateInfo) in
handler(link, info)
}
}
}
15 changes: 15 additions & 0 deletions Sources/UpdateLink/UpdateLink.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import UIKit

@MainActor
public protocol UpdateLink: AnyObject {
var isEnabled: Bool { get set }
var requiresContinuousUpdates: Bool { get set }
var preferredFrameRateRange: CAFrameRateRange { get set }
func addAction(handler: @escaping (any UpdateLink, any UpdateInfo) -> Void)
}

@MainActor
public protocol UpdateInfo: AnyObject {
var modelTime: TimeInterval { get }
}

0 comments on commit 1a173a8

Please sign in to comment.