JEL JEL - 7 months ago 48
Swift Question

Dynamic UIBezierPath for Animations

I want to create an animation where an object animates its position along a

path
. The trouble I am having is making this
path
dynamic meaning that it works on all screen sizes.

The spaceship in the gif above follows a "U" shape
path
initially.

I use this "U" shape
path
and it works, here is the code:

func animateAlongPath() {
// Create and add image to view
let flyingSaucerImage = UIImage(named: "flying-saucer")!
let flyingSaucerImageView = UIImageView(image: flyingSaucerImage)

flyingSaucerImageView.frame = CGRect(x: 100, y: 100, width: flyingSaucerImage.size.width, height: flyingSaucerImage.size.height)
holderView.addSubview(flyingSaucerImageView)

// Create "U" shape path for animation (path code created in PaintCode)
let path = UIBezierPath()
path.moveToPoint(CGPointMake(59.5, 81.5))
path.addCurveToPoint(CGPointMake(66.5, 91.5), controlPoint1: CGPointMake(63.64, 84.13), controlPoint2: CGPointMake(62.62, 85.9))
path.addCurveToPoint(CGPointMake(81.5, 110.5), controlPoint1: CGPointMake(72.31, 99.88), controlPoint2: CGPointMake(75.91, 103.08))
path.addCurveToPoint(CGPointMake(109.5, 142.5), controlPoint1: CGPointMake(88.44, 119.71), controlPoint2: CGPointMake(102.39, 135.23))
path.addCurveToPoint(CGPointMake(145.5, 156.5), controlPoint1: CGPointMake(122.47, 155.76), controlPoint2: CGPointMake(129.15, 157.54))
path.addCurveToPoint(CGPointMake(237.5, 81.5), controlPoint1: CGPointMake(185.04, 153.99), controlPoint2: CGPointMake(237.5, 81.5))

let pathAnimation = CAKeyframeAnimation(keyPath: "position")
pathAnimation.path = path.CGPath // Use "U" shape path for animation
pathAnimation.calculationMode = kCAAnimationPaced
pathAnimation.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)]
pathAnimation.duration = 1
pathAnimation.removedOnCompletion = false
pathAnimation.fillMode = kCAFillModeForwards

flyingSaucerImageView.layer.addAnimation(pathAnimation, forKey: nil)
flyingSaucerImageView.layer.position = path.currentPoint
}


The problem is that the
UIBezierPath
is not dynamic. It works great on the iPhone 6 device screen size, but does not work great on any other device size since it is static. I tried using PaintCode to create dynamic paths with variables, but just can't get it to work.

Any ideas?

Answer

PaintCode can generate code for resizable UIBezierPaths using Frames.

Put the Bezier inside a Frame object and then set desired autoresizing springs (all flexible). The resulting code will be parametrized with CGRect/NSRect and will use relative coefficients to calculate bezier points.

There’s also a video tutorial about Dynamic Shapes if you want to get more into depth.

PaintCode Bezier in Frame