Swift 3 CGRect 上的 CGAffineTransform

Swift 3 CGAffineTransform on CGRect

基本上我的目标是在我的徽标周围做一个类似原子的运动 https://media.giphy.com/media/9oHZQ2gEez8ti/giphy.gif

let rect = CGRect(origin: CGPoint(x: Logo.position.x - (Logo.frame.width/3.6), y: Logo.position.y - (Logo.frame.height/2) - kViewSize.height/32), size: CGSize(width: Logo.frame.width/2, height: Logo.frame.height + kViewSize.height/16))
let ellipse = CGPath(ellipseIn: rect, transform: nil)
YellowMagic.run(SKAction.repeatForever(SKAction.follow(ellipse, asOffset: false, orientToPath: false, duration: 1.5)))

通过上面的代码,我得到了中间的椭圆,精灵根据需要围绕路径运行。

问题是通过旋转路径得到另外两个椭圆。我不认为旋转路径是可能的,所以我尝试使用以下代码旋转矩形。

var rect2 = rect
rect2 = rect2.applying(CGAffineTransform(rotationAngle: CGFloat(M_PI/4)))
let ellipse2 = CGPath(ellipseIn: rect2, transform: nil)

上面的代码并没有旋转矩形,实际上它使矩形变成了正方形。必须有一个我在这里缺少的更简单的解决方案。非常感谢任何帮助。谢谢!

Goal to achieve

My Xcode example project

https://github.com/junaidios/Oval-path-Animation

动画视图

https://github.com/junaidios/Oval-path-Animation/blob/master/JSAnimation/animation/JSCircleAnimtionView.swift

My try

添加中心圆

   let centerCirclePath = UIBezierPath(ovalIn: CGRect(x: 162, y: 188, width: 20, height: 20))
   colorCircleLayerCenter.setFill()
   centerCirclePath.fill()

添加椭圆

    let bezierPath1 = UIBezierPath()
    bezierPath1.move(to: CGPoint(x: 145.5, y: 213.93))
    bezierPath1.addCurve(to: CGPoint(x: 84.68, y: 131.46), controlPoint1: CGPoint(x: 83.75, y: 163.11), controlPoint2: CGPoint(x: 79.26, y: 136.87))
    bezierPath1.addCurve(to: CGPoint(x: 193.5, y: 178.49), controlPoint1: CGPoint(x: 87.4, y: 128.75), controlPoint2: CGPoint(x: 130.21, y: 128.39))
    bezierPath1.addCurve(to: CGPoint(x: 258.01, y: 269.86), controlPoint1: CGPoint(x: 256.33, y: 228.23), controlPoint2: CGPoint(x: 262.32, y: 266.63))
    bezierPath1.addCurve(to: CGPoint(x: 145.5, y: 213.93), controlPoint1: CGPoint(x: 249.34, y: 276.35), controlPoint2: CGPoint(x: 207.25, y: 264.75))
    bezierPath1.close()

    let bezierPath2 = UIBezierPath()
    bezierPath2.move(to: CGPoint(x: 145.5, y: 184.8))
    bezierPath2.addCurve(to: CGPoint(x: 254.5, y: 131.5), controlPoint1: CGPoint(x: 195.5, y: 146.16), controlPoint2: CGPoint(x: 238.27, y: 131.5))
    bezierPath2.addCurve(to: CGPoint(x: 200.5, y: 217.47), controlPoint1: CGPoint(x: 262.64, y: 131.5), controlPoint2: CGPoint(x: 261.5, y: 159.92))
    bezierPath2.addCurve(to: CGPoint(x: 84.5, y: 272.49), controlPoint1: CGPoint(x: 139.94, y: 274.6), controlPoint2: CGPoint(x: 91.01, y: 272.49))
    bezierPath2.addCurve(to: CGPoint(x: 145.5, y: 184.8), controlPoint1: CGPoint(x: 71.42, y: 272.49), controlPoint2: CGPoint(x: 95.5, y: 223.44))
    bezierPath2.close()

    let bezierPath3 = UIBezierPath()
    bezierPath3.move(to: CGPoint(x: 143.5, y: 201.45))
    bezierPath3.addCurve(to: CGPoint(x: 172, y: 89.5), controlPoint1: CGPoint(x: 143.5, y: 154.31), controlPoint2: CGPoint(x: 155.77, y: 89.5))
    bezierPath3.addCurve(to: CGPoint(x: 200.5, y: 201.45), controlPoint1: CGPoint(x: 180.14, y: 89.5), controlPoint2: CGPoint(x: 200.5, y: 124.29))
    bezierPath3.addCurve(to: CGPoint(x: 172, y: 307.5), controlPoint1: CGPoint(x: 200.5, y: 278.04), controlPoint2: CGPoint(x: 178.51, y: 307.5))
    bezierPath3.addCurve(to: CGPoint(x: 143.5, y: 201.45), controlPoint1: CGPoint(x: 158.92, y: 307.5), controlPoint2: CGPoint(x: 143.5, y: 248.58))
    bezierPath3.close()

    let linLayer1 = CAShapeLayer()
    linLayer1.path = bezierPath1.cgPath;
    linLayer1.strokeColor = colorLine.cgColor
    linLayer1.fillColor = UIColor.clear.cgColor

    self.layer.addSublayer(linLayer1);

    let lineLayer2 = CAShapeLayer()
    lineLayer2.path = bezierPath2.cgPath;
    lineLayer2.strokeColor = colorLine.cgColor
    lineLayer2.fillColor = UIColor.clear.cgColor

    self.layer.addSublayer(lineLayer2);

    let lineLayer3 = CAShapeLayer()
    lineLayer3.path = bezierPath3.cgPath;
    lineLayer3.strokeColor = colorLine.cgColor
    lineLayer3.fillColor = UIColor.clear.cgColor

    self.layer.addSublayer(lineLayer3);

在椭圆上添加移动圆圈

    let circleLayer1 = CAShapeLayer()
    circleLayer1.path = UIBezierPath(ovalIn: CGRect(x: -10, y: -10, width: 20, height: 20)).cgPath;
    circleLayer1.fillColor = colorCircleLayer1.cgColor

    let circleLayer2 = CAShapeLayer()
    circleLayer2.path = UIBezierPath(ovalIn: CGRect(x: -10, y: -10, width: 20, height: 20)).cgPath;
    circleLayer2.fillColor = colorCircleLayer2.cgColor

    let circleLayer3 = CAShapeLayer()
    circleLayer3.path = UIBezierPath(ovalIn: CGRect(x: -10, y: -10, width: 20, height: 20)).cgPath;
    circleLayer3.fillColor = colorCircleLayer3.cgColor

    self.layer.addSublayer(circleLayer1);
    self.layer.addSublayer(circleLayer2);
    self.layer.addSublayer(circleLayer3);

将动画应用于圆圈

    circleLayer1.add(self.addAnimation(ovalPath: bezierPath1), forKey: "1");
    circleLayer2.add(self.addAnimation(ovalPath: bezierPath2), forKey: "2");
    circleLayer3.add(self.addAnimation(ovalPath: bezierPath3), forKey: "3");

动画功能

func addAnimation(ovalPath : UIBezierPath) -> CAKeyframeAnimation {

    let animation = CAKeyframeAnimation()

    animation.keyPath = "position"
    animation.repeatCount = HUGE
    animation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear);
    animation.fillMode = kCAFillModeForwards;
    animation.repeatCount = .infinity
    animation.beginTime = 0.0
    animation.duration = 2.5
    animation.calculationMode = kCAAnimationPaced

    animation.path = ovalPath.cgPath

    return animation;
}

Final output

我修改了找到的函数 here 并生成了以下函数:

func createPathRotatedAroundBoundingBoxCenter(path: CGPath, radians: CGFloat) -> CGPath {
    let bounds = path.boundingBox; // might want to use   CGPathGetPathBoundingBox
    let center = CGPoint(x: bounds.midX, y: bounds.midY)
    var transform = CGAffineTransform(translationX: 0, y: 0)
    transform = transform.translatedBy(x: center.x, y: center.y)
    transform = transform.rotated(by: radians)
    transform = transform.translatedBy(x: -center.x, y: -center.y)
    return path.copy(using: &transform)!
}

然后我修改了我的代码以获得所需的结果。

let rect = CGRect(origin: CGPoint(x: Logo.position.x - (Logo.frame.width/3.6), y: Logo.position.y - (Logo.frame.height/2) - kViewSize.height/32), size: CGSize(width: Logo.frame.width/2, height: Logo.frame.height + kViewSize.height/16))
let ellipse = CGPath(ellipseIn: rect, transform: nil)
let ellipse2a = CGPath(ellipseIn: rect, transform: nil)
let ellipse3a = CGPath(ellipseIn: rect, transform: nil)
let ellipse2 = createPathRotatedAroundBoundingBoxCenter(path: ellipse2b, radians: CGFloat(M_PI/4.0))
let ellipse3 = createPathRotatedAroundBoundingBoxCenter(path: ellipse3b, radians: CGFloat(-M_PI/4.0))
YellowMagic.run(SKAction.repeatForever(SKAction.follow(ellipse, asOffset: false, orientToPath: false, duration: 1)))
RedMagic.run(SKAction.repeatForever(SKAction.follow(ellipse2, asOffset: false, orientToPath: false, duration: 1)))
GreenMagic.run(SKAction.repeatForever(SKAction.follow(ellipse3, asOffset: false, orientToPath: false, duration: 1)))