沿较大的弧形路径移动弧形段路径。迅速

时间:2020-07-20 19:19:18

标签: swift path core-animation automatic-ref-counting

我正在尝试制作使弧段路径(绿色部分)沿着“母亲”弧形路径(红色部分)移动的动画。

mainView

这里是完整的存储库:https://github.com/gmb55/movingArcs

完整代码:

simulate

当绿色弧形代码看起来像这样时,它正在移动,但位置错误,而不是沿着红色路径。 https://media.giphy.com/media/loSPpw2TPNNJyXSqcO/giphy.gif

当我将转换设置为此:

wrapper.find('MyInput[name="email"]').simulate('change', {target: {
            name: 'email', value: 'ale@gmail.com' }})

它在正确的路径上移动,但旋转错误: https://media.giphy.com/media/S85AIcXObCMfOhAjEe/giphy.gif

当我将转换设置为此:


import UIKit

class MovingArcs: UIView {
    var path: UIBezierPath!
    var shapeLayer: CAShapeLayer!
    var movement: CAKeyframeAnimation!

    // set path for moving and draw it on screen
    func pathShapeLayer() -> UIBezierPath {
        let startDegree = 180.0
        let endDegree = 360.0
        let start = CGFloat(startDegree).toRadians()
        let end = CGFloat(endDegree).toRadians()

        path = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100),
            radius: 100.0,
            startAngle: start,
            endAngle: end,
            clockwise: true)

        let pathShapeLayer = CAShapeLayer()
        pathShapeLayer.path = path.cgPath
        pathShapeLayer.fillColor = UIColor.clear.cgColor
        pathShapeLayer.lineWidth = CGFloat(4)
        pathShapeLayer.strokeColor = UIColor.red.cgColor
        pathShapeLayer.position = .init(x: 0, y: 0)

        self.layer.addSublayer(pathShapeLayer)

        return path
    }

    // set movemnet along path with rotation
    func addAnimation() {
        let movement = CAKeyframeAnimation(keyPath: "position")
        movement.path = pathShapeLayer().cgPath
        movement.duration = 3
        movement.repeatCount = 1
        movement.rotationMode = CAAnimationRotationMode.rotateAuto
        movement.calculationMode = CAAnimationCalculationMode.paced
        movement.timingFunctions = [CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)]
        self.movement = movement
    }

    // set path for arc that will be moving
    func movingArc() -> UIBezierPath {
        let startDegree = 180.0
        let endDegree = 210.0
        let start = CGFloat(startDegree).toRadians()
        let end = CGFloat(endDegree).toRadians()

        let arcPath = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100),
            radius: 100.0,
            startAngle: start,
            endAngle: end,
            clockwise: true)

        return arcPath
    }

    // draw shapeLayer for moving arc
    func movingArcLayer() -> CAShapeLayer {
        let color = UIColor.green

        let backgroundCircleLayer = CAShapeLayer()
        backgroundCircleLayer.path = movingArc().cgPath
        backgroundCircleLayer.fillColor = UIColor.clear.cgColor
        backgroundCircleLayer.strokeColor = color.cgColor
        backgroundCircleLayer.lineWidth = 4.0
        backgroundCircleLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
      //  backgroundCircleLayer.position = CGPoint(x: 0, y: 100)
      //  backgroundCircleLayer.transform = CATransform3DMakeTranslation(0, -100, 0)
      //  backgroundCircleLayer.transform = CATransform3DMakeRotation(CGFloat(-180).toRadians(), 0, 0, 1)

        self.layer.addSublayer(backgroundCircleLayer)

        return backgroundCircleLayer
    }

    // init for animation
    func initiateAnimation() {
        let layer = movingArcLayer()
        layer.add(self.movement, forKey: "Object Movement")
    }

    init() {
        super.init(frame: .zero)
        addAnimation()
        movingArcLayer()
        initiateAnimation()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

extension CGFloat {
    func toRadians() -> CGFloat {
        return self * CGFloat(Double.pi) / 180.0
    }
}

它在错误的路径上移动(偏移90度),但旋转正确。 https://media.giphy.com/media/mEEWv5i32TELTseyQG/giphy.gif

问题是,我应该如何正确设置图层变换,也许您知道很好的教程来解释CoreAnimation的工作原理?

1 个答案:

答案 0 :(得分:2)

问题在于如何声明绿色弧的路径。以前它是一条粗曲线。但现在是2D平面。

下面的工作代码:

import UIKit

class MovingRect: UIView {
    var path: UIBezierPath!
    var shapeLayer: CAShapeLayer!
    var movement: CAKeyframeAnimation!

    // set path for moving and draw it on screen
    func pathShapeLayer() -> UIBezierPath {
        let startDegree = 180.0
        let endDegree = 360.0
        let start = CGFloat(startDegree).toRadians()
        let end = CGFloat(endDegree).toRadians()

        path = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100),
            radius: 100.0,
            startAngle: start,
            endAngle: end,
            clockwise: true)

        let pathShapeLayer = CAShapeLayer()
        pathShapeLayer.path = path.cgPath
        pathShapeLayer.fillColor = UIColor.clear.cgColor
        pathShapeLayer.lineWidth = CGFloat(4)
        pathShapeLayer.strokeColor = UIColor.red.cgColor
        pathShapeLayer.position = .init(x: 0, y: 0)

        self.layer.addSublayer(pathShapeLayer)

        return path
    }

    // set movemnet along path with rotation
    func addAnimation() {
        let movement = CAKeyframeAnimation(keyPath: "position")
        movement.path = pathShapeLayer().cgPath
        movement.duration = 2
        movement.repeatCount = 1
        movement.rotationMode = CAAnimationRotationMode.rotateAuto
        movement.calculationMode = CAAnimationCalculationMode.paced
        movement.timingFunctions = [CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)]
        self.movement = movement
    }
    
    func movingArcPath() -> UIBezierPath {
        let startDegree = 255.0
        let endDegree = 285.0
        let start = CGFloat(startDegree).toRadians()
        let end = CGFloat(endDegree).toRadians()

        path = UIBezierPath()
      
        path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 110, startAngle: start, endAngle: end, clockwise: true)
        path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 90, startAngle: end, endAngle: start, clockwise: false)
        path.close()
        
        return path
    }
    
    // draw shapeLayer for moving arc
    func movingArcLayer() -> CAShapeLayer {
        let color = UIColor.green

        let movingRectLayer = CAShapeLayer()
        movingRectLayer.path = movingArcPath().cgPath
        movingRectLayer.fillColor = color.cgColor
        movingRectLayer.strokeColor = color.cgColor
        movingRectLayer.lineWidth = 4.0
        movingRectLayer.transform = CATransform3DMakeTranslation(-100, 0, 0)
        movingRectLayer.position = CGPoint(x: 200, y: 100)
        movingRectLayer.anchorPoint = CGPoint(x: 200, y: 100)
     //   movingRectLayer.transform = CATransform3DMakeRotation(CGFloat(90).toRadians(), 0, 0, 1)
    
        self.layer.addSublayer(movingRectLayer)

        return movingRectLayer
    }

    // init for animation
    func initiateAnimation() {
        let layer = movingArcLayer()
        layer.add(self.movement, forKey: "Object Movement")
    }

    init() {
        super.init(frame: .zero)
        addAnimation()
        initiateAnimation()
      //  removeArcLayer()
        
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}