【问题标题】:Quickly updating UIView background color in Swift?在 Swift 中快速更新 UIView 背景颜色?
【发布时间】:2017-03-09 13:43:37
【问题描述】:

我有一个 UIView 的背景颜色应该改变颜色的时间数组。该数组包含 0-10000ms 的值,其中每个索引是第一次更改和当前更改之间的持续时间。我已经实现了一个循环来在预定的时间执行任务,并且使用打印语句,它似乎正在工作。但是,背景颜色只会变为最后一种颜色,而不是不断变化。

我相信这是因为在循环完成之前背景颜色不会更新。这是否正确,如果正确,我该如何解决?

    sendingView.backgroundColor = UIColor.black
    let startingTime = getCurrentMillis()
    var found = false
    for time in receivingMsgData {
        while(!found) {
            let curDuration = getCurrentMillis() - startingTime
            if curDuration > time {
                if(sendingView.backgroundColor == UIColor.black) {
                    sendingView.backgroundColor = UIColor.white
                    print("playing at \(getCurrentMillis()-startingTime) turning white")
                } else {
                    sendingView.backgroundColor = UIColor.black
                    print("playing at \(getCurrentMillis()-startingTime) turning black")
                }
                found = true
            }
        }
        found = false
    }

【问题讨论】:

  • 在颜色改变后尝试在视图上调用 setNeedsDisplay() 方法。
  • 尝试在'UIView.animate(withDuration: ) { }'中编写代码
  • 这段代码是在异步还是主线程上执行的?
  • @GirishNair 在主线程上。
  • @JustinChang:检查更新的代码

标签: ios iphone swift


【解决方案1】:

试试这样的

DispatchQueue.global(qos: .userInitiated).async {
    let delay:TimeInterval = 0.01 // Seconds
    for index in 0..<100 {
        if index % 2 == 0 {
            Thread.sleep(forTimeInterval: delay)
            DispatchQueue.main.async {
                self.view.backgroundColor = UIColor.white
                print("white")
            }
        }else{
            Thread.sleep(forTimeInterval: delay)
            DispatchQueue.main.async {
                self.view.backgroundColor = UIColor.black
                print("black")
            }
        }
    }
}

在异步线程中执行您的操作并更改主线程的颜色 您在主线程中做了很多工作导致它挂起,还设置了一些延迟以便用户可以查看动画

在你的情况下尝试这样的事情

let delay:TimeInterval = 0.01 // Seconds
sendingView.backgroundColor = UIColor.black
let startingTime = getCurrentMillis()
var found = false
DispatchQueue.global(qos: .userInitiated).async {
    for time in receivingMsgData {
        while(!found) {
            let curDuration = getCurrentMillis() - startingTime
            if curDuration > time {
                if(sendingView.backgroundColor == UIColor.black) {
                    Thread.sleep(forTimeInterval: delay)
                    DispatchQueue.main.async {
                        sendingView.backgroundColor = UIColor.white
                        print("playing at \(getCurrentMillis()-startingTime) turning white")
                    }
                } else {
                    Thread.sleep(forTimeInterval: delay)
                    DispatchQueue.main.async {
                        sendingView.backgroundColor = UIColor.black
                        print("playing at \(getCurrentMillis()-startingTime) turning black")
                    }
                }
                found = true
            }
        }
        found = false
    }
}

【讨论】:

    【解决方案2】:

    您发布的代码在设置颜色时阻塞了主线程或操作不在主线程上。这两种情况很可能在整个循环执行完成之前或什至在一段时间后都不会发生任何变化。

    当您处理在某个时间安排的可能与屏幕更新速度无关的数据时,您需要在屏幕刷新时按需提供颜色。

    在您的情况下,我建议使用显示链接CADisplayLink,该链接旨在在屏幕刷新时触发。您甚至可以从显示链接本身获取自开始以来的当前时间值。可以像在代码中使用 curDuration 一样使用该经过的时间。假设其余代码工作正常。

    【讨论】:

      【解决方案3】:

      我相信这是因为在循环完成之前背景颜色不会更新。这是正确的

      是的,是的。在主线程上的所有代码完成 并且提交 CATransaction 之前,不会进行绘图。您需要做以下两件事之一:

      • 在后台线程上运行耗时的代码,进入主线程只是为了与界面对话并设置颜色。

      • 使用某种形式的延迟让主线程离开足够长的时间,以便在继续“循环”之前进行绘制。

      【讨论】:

        猜你喜欢
        • 2021-12-15
        • 2014-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-02
        • 1970-01-01
        • 2013-02-22
        • 1970-01-01
        相关资源
        最近更新 更多