【问题标题】:Dispatch Semaphore for UI为 UI 分配信号量
【发布时间】:2021-07-16 15:13:28
【问题描述】:

我想为 uiviews 的 alpha 设置动画,但我似乎无法做到。它的行为很奇怪,并说不建议在后台线程上运行正在运行的 UI 更改,但我不知道如何让它在主线程上运行。有人可以帮助我吗?我相信它会跳过第一个 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()
    }
}

}

【问题讨论】:

    标签: ios swift asynchronous dispatchsemaphore


    【解决方案1】:

    您需要在主线程中插入任何与 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
            
        }
    }
    

    【讨论】:

    • 我明白你的意思,但我想让它以某种方式正确编写。没有其他方法可以不将所有内容写入其他代码部分的完成块吗?当它这样写的时候,它只是压倒性的,而且不那么容易阅读。
    • 来自上一个动画。一个完成,第二个启动 5 秒计时器,然后播放。
    • 我试过了,但它跳过了第 43 行到第 59 行,然后是第 50 行。
    • 我明白了,但我可以避免将所有内容粘贴到完成处理程序中,还是没有办法?
    【解决方案2】:

    您还可以创建用于创建动画的配置(可以在此处找到草稿) 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多