我有一个称为UIView
的View
子类,其中我希望“波纹”从用户双击的位置向外移动(以及执行其他绘图功能)。目前,这是我的draw
方法的相关部分:
override func draw(_ rect: CGRect) {
for r in ripples {
r.paint()
}
}
这是
r.paint()
类中Ripple
的实现方式:func paint() {
let c = UIColor(white: CGFloat(1.0 - (Float(iter))/100), alpha: CGFloat(1))
print(iter, " - ",Float(iter)/100)
c.setFill()
view.fillCircle(center: CGPoint(x:x,y:y), radius: CGFloat(iter))
}
iter
应该由Timer
的构造函数中启动的Ripple
每0.1秒递增一次:Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: move)
move
的实现如下:func move(_ timer: Timer) {
while (tier<100) {
iter += 1
DispatchQueue.main.async {
self.view.setNeedsDisplay()
}
}
timer.invalidate()
}
应该发生的情况是,计时器启动时每隔0.1秒,它将增加
iter
并告诉View
重新绘制,然后它将使用Ripple.paint()
方法执行此操作,该方法使用iter
来确定圆的颜色和半径。但是,正如使用
print
语句所揭示的,相反,发生的是Timer
在重绘实际发生之前全部触发了100次。我尝试通过将DispatchQueue.main.async
替换为DispatchQueue.main.sync
来处理此问题,但这只是使应用程序挂起。我究竟做错了什么?如果这不是解决问题的正确方法,那么当应用程序仍可以执行其他功能(例如产生更多波纹)时,如何进行平滑的波纹动画(涉及更改颜色时会增大的圆)? (这意味着多个波纹必须能够同时工作。) 最佳答案
您可以使用CABasicAnimation
和自定义CALayer
实现所需的功能,如下所示:
class MyLayer : CALayer
{
var iter = 0
override class func needsDisplay(forKey key: String) -> Bool
{
let result = super.needsDisplay(forKey: key)
return result || key == "iter"
}
override func draw(in ctx: CGContext) {
UIGraphicsPushContext(ctx)
UIColor.red.setFill()
ctx.fill(self.bounds)
UIGraphicsPopContext()
NSLog("Drawing, \(iter)")
}
}
class MyView : UIView
{
override class var layerClass: Swift.AnyClass {
get {
return MyLayer.self
}
}
}
class ViewController: UIViewController {
let myview = MyView()
override func viewDidLoad() {
super.viewDidLoad()
myview.frame = self.view.bounds
self.view.addSubview(myview)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let animation = CABasicAnimation(keyPath: "iter")
animation.fromValue = 0
animation.toValue = 100
animation.duration = 10.0
myview.layer.add(animation, forKey: "MyIterAnimation")
(myview.layer as! MyLayer).iter = 100
}
}
关于ios - (快速3)-如何在自定义UIView中包含动画,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42869984/