为 UI 分派信号量

Dispatch Semaphore for UI

我想为 uiviews 的 alpha 设置动画,但我似乎做不到。它的行为很奇怪,并说错误 运行ning UI changes arent recommended to be 运行 on background thread,但我不知道如何在主线程上做到 运行 .有人可以帮我吗?我相信它会跳过第一个 UIView.animate 块并在没有任何动画的情况下执行第二个块。

func animateSemaphore() {

circleRed.alpha = 0.2
circleOrange.alpha = 0.2
circleGreen.alpha = 1

let dispatchSemaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue.global(qos: .background)

dispatchQueue.async {
    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
        self.circleGreen.alpha = 0.2
    } completion: { (_) in
        print("1")
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 3, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 1
    } completion: { (_) in
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
    } completion: { (_) in
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 1, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 0.2
        self.circleGreen.alpha = 1
    } completion: { (_) in
        self.animateSemaphore()
    }
}

}

您需要在主线程而不是后台队列中插入任何 ui/animate 相关代码

func animateSemaphore() {
    circleRed.alpha = 0.2
    circleOrange.alpha = 0.2
    circleGreen.alpha = 1
        
    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
        self.circleGreen.alpha = 0.2
    } completion: { (_) in
        UIView.animate(withDuration: 0.5, delay: 3, options: .curveEaseInOut) {
            self.circleOrange.alpha = 0.2
            self.circleRed.alpha = 1
        } completion: { (_) in
            UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
                self.circleOrange.alpha = 1
            } completion: { (_) in
                UIView.animate(withDuration: 0.5, delay: 1, options: .curveEaseInOut) {
                    self.circleOrange.alpha = 0.2
                    self.circleRed.alpha = 0.2
                    self.circleGreen.alpha = 1
                } completion: { (_) in 
                }
            }
        }
    }
 }

或使用 delay 而不是嵌套动画

func animateSemaphore() {

    circleRed.alpha = 0.2
    circleOrange.alpha = 0.2
    circleGreen.alpha = 1

    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
        self.circleGreen.alpha = 0.2
    } completion: { (_) in
        print("1")
      
    }
    
   
    UIView.animate(withDuration: 0.5, delay: 8.5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 1
    } completion: { (_) in
        
    }
    
   
    UIView.animate(withDuration: 0.5, delay: 14, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
    } completion: { (_) in
       
    }
    
  
    UIView.animate(withDuration: 0.5, delay: 15.5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 0.2
        self.circleGreen.alpha = 1
    } completion: { (_) in
        
    }
}

您还可以创建用于创建动画的配置(可以在此处找到草稿) https://gist.github.com/maximkrouk/76163b3f2775dafc73c5633d155368cb 并添加一些扁平化

public struct UIViewAnimation {
    private init(
        provider: UIViewAnimatiorProvider?,
        animations: @escaping () -> Void,
        completion: ((Bool) -> Void)? = nil
    ) {
        self.provider = provider
        self.animations = animations
        self.completion = completion
    }
    
    public init(
        config: UIViewAnimatiorProvider,
        animations: @escaping () -> Void,
        completion: ((Bool) -> Void)? = nil
    ) {
        self.init(
            provider: config,
            animations: animations,
            completion: completion
        )
    }
    
    let provider: UIViewAnimatiorProvider?
    let animations: () -> Void
    let completion: ((Bool) -> Void)?
    
    public func run() {
        if let provider = provider {
            provider.makeAnimator(
                for: animations,
                completion: completion ?? { _ in }
            ).animate()
        } else {
            animations()
            completion?(true)
        }
    }
    
    public func appendingCompletion(_ completion: @escaping (Bool) -> Void) -> UIViewAnimation {
        UIViewAnimation(
            provider: provider,
            animations: animations,
            completion: { isFinished in
                self.completion?(isFinished)
                completion(isFinished)
            }
        )
    }
    
    public static let empty: UIViewAnimation = .init(
        provider: nil,
        animations: {},
        completion: nil
    )
}

extension UIViewAnimation {
    public static func sequence(_ animations: UIViewAnimation...) -> UIViewAnimation {
        guard var animation = animations.last else { return .empty }
        animations.dropLast().reversed().forEach { prevAnimation in
            let animate = animation.run
            animation = prevAnimation.appendingCompletion { _ in animate() }
        }
        return animation
    }
}

并像

一样使用它
extension UIView {
    func animateSemaphore() {
        let initialBackground = backgroundColor
        UIViewAnimation.sequence(
            UIViewAnimation(config: .init(duration: 2)) {
                self.backgroundColor = .red
            },
            UIViewAnimation(config: .init(duration: 2)) {
                self.backgroundColor = .green
            },
            UIViewAnimation(config: .init(duration: 2)) {
                self.backgroundColor = .red
            },
            UIViewAnimation(config: .init(duration: 2)) {
                self.backgroundColor = .green
            },
            UIViewAnimation(config: .init(duration: 2)) {
                self.backgroundColor = initialBackground
            }
        ).run()
    }
}

UIView().animateSemaphore()