我有一个称为UIViewView子类,其中我希望“波纹”从用户双击的位置向外移动(以及执行其他绘图功能)。目前,这是我的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/

10-11 23:35