Last active
October 19, 2022 13:21
-
-
Save yucelokan/01212dfbf7a188523fd74ae06fd09875 to your computer and use it in GitHub Desktop.
A general hack to prevent Lottie animations from stopping playing after pushing/popping/presenting/dismissing.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A general hack to prevent Lottie animations from stopping playing after pushing/popping/presenting/dismissing. | |
// Usage: LottieFinder.setupLottieFinder() | |
import UIKit | |
import Lottie | |
class LottieFinder { | |
static private var operationQueue = OperationQueue() | |
static private var operations: [Operation] = [] | |
static func setupLottieFinder() { | |
UIViewController.subscribeLotties() | |
} | |
static func operation(from: UIViewController) { | |
operationQueue.cancelAllOperations() | |
operations.removeAll() | |
let operation = LottieFinderOperation(viewController: from) | |
operations.append(contentsOf: [operation]) | |
operationQueue.addOperation(operation) | |
} | |
} | |
extension UIViewController { | |
@objc private dynamic func swizzledLottieViewWillAppear(_ animated: Bool) { | |
swizzledLottieViewWillAppear(animated) | |
LottieFinder.operation(from: self) | |
} | |
internal static func subscribeLotties() { | |
swizzleLottieViewWillAppear() | |
} | |
private static func swizzleLottieViewWillAppear() { | |
let selector1 = #selector(UIViewController.viewWillAppear(_:)) | |
let selector2 = #selector(UIViewController.swizzledLottieViewWillAppear(_:)) | |
let originalMethod = class_getInstanceMethod(UIViewController.self, selector1)! | |
let swizzleMethod = class_getInstanceMethod(UIViewController.self, selector2)! | |
method_exchangeImplementations(originalMethod, swizzleMethod) | |
} | |
} | |
class LottieFinderOperation: Operation { | |
init(viewController: UIViewController) { | |
self.viewController = viewController | |
} | |
weak private var viewController: UIViewController? | |
override func main() { | |
guard !isCancelled else { return } | |
DispatchQueue.main.async { [weak self] in | |
guard let `self` = self, let view = self.viewController?.view else { return } | |
for lottie in self.subviews( | |
in: view, ofType: AnimationView.self | |
) where lottie.superview != nil { | |
guard !self.isCancelled else { break } | |
lottie.play() | |
} | |
} | |
} | |
private func subviews<T: UIView>(in view: UIView, ofType whatType: T.Type) -> [T] { | |
var tViews: [T] = [] | |
for subview in view.subviews { | |
guard !isCancelled else { break } | |
if let tView = subview as? T { | |
tViews.append(tView) | |
} else { | |
tViews.append(contentsOf: subviews(in: subview, ofType: whatType)) | |
} | |
} | |
return isCancelled ? [] : tViews | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment