Search code examples
swiftuibezierpathcashapelayercabasicanimationanimatewithduration

How to animate the end and the control points SWIFT


I have a CAShapeLayer im my view which has the to CGPath casted path of an instance of an Bezierpath. I now want to animate the end and the two control points so e.g. the end of that line is moving(not stopping). How to do that? I looked at CABasicAninmations but did not get how the access the end point. The same with animate with duration. How to make this happen for an endlessness time.


Solution

  • You can use a CADisplayLink (it's like a NSTimer, except optimally timed for animation frame updates) and update the path of the CAShapeLayer.


    For example:

    var displayLink: CADisplayLink?
    var startTime: CFAbsoluteTime?
    let duration = 2.0
    
    var shapeLayer: CAShapeLayer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        shapeLayer = CAShapeLayer()
        shapeLayer?.fillColor = UIColor.clearColor().CGColor
        shapeLayer?.strokeColor = UIColor.blueColor().CGColor
        shapeLayer?.lineWidth = 10
        shapeLayer?.frame = view.bounds
        view.layer.addSublayer(shapeLayer!)
    
        startTime = CFAbsoluteTimeGetCurrent()
        displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
        displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
    }
    
    func handleDisplayLink(displayLink: CADisplayLink) {
        let elapsed = CFAbsoluteTimeGetCurrent() - startTime!
        let percent = (elapsed % duration) / duration
    
        let path = UIBezierPath()
        let startPoint = CGPoint(x: 0, y: view.bounds.size.height / 2.0)
        let controlPoint = CGPoint(x: view.bounds.size.width / 20, y: view.bounds.size.height * CGFloat(0.5 + sin(percent * M_PI * 2.0) / 2.0))
        let endPoint = CGPoint(x: view.bounds.size.width - 1, y: view.bounds.size.height / 2.0)
        path.moveToPoint(startPoint)
        path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint)
    
        shapeLayer?.path = path.CGPath
    }
    

    That yields:

    enter image description here