Swift:沿动画路径对对象进行动画处理

彼得·舍夫奇克

我想为围绕圆以脉冲方式旋转的小红点设置动画(从小到大,然后从小开始)。似乎小点一直围绕原始形状旋转,并且没有考虑到它在扩大的圆圈...我在代码中有这个:

// MARK: - Properties

  private lazy var containerView = UIView()

  let littleCircleRadius: CGFloat = 10

  private lazy var littleRedDot: CALayer = {
    let layer = CALayer()
    layer.backgroundColor = UIColor.red.cgColor
    let littleDotSize = CGSize(width: 10, height: 10)
    layer.frame = CGRect(x: containerView.bounds.center.x - littleDotSize.width / 2,
                         y: containerView.bounds.center.y - littleCircleRadius - littleDotSize.width/2 ,
                         width: littleDotSize.width,
                         height: littleDotSize.height)
    return layer
  }()

 private lazy var littleCircleLayer: CAShapeLayer = {
    let layer = CAShapeLayer()
    layer.lineWidth = 1.5
    layer.lineCap = .round
    layer.strokeColor = UIColor.black.cgColor
    layer.fillColor = UIColor.clear.cgColor
    return layer
  }()

// MARK: - Setup
 func setup() {
    view.addSubview(containerView)
    containerView.frame = CGRect(x: 40, y: 200, width: 300, height: 300)
    containerView.backgroundColor = UIColor.gray.withAlphaComponent(0.2)

    littleCircleLayer.path = makeArcPath(arcCenter: containerView.bounds.center, radius: 10)
    containerView.layer.addSublayer(littleCircleLayer)
    containerView.layer.addSublayer(littleRedDot)
}

// MARK: - Animations
func animate() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    animateLittleRedDotRotation()
    animateCircleExpanding()
    CATransaction.commit()
}

func animateLittleRedDotRotation() {
    let anim = CAKeyframeAnimation(keyPath: "position")
    anim.duration = 1.5
    anim.rotationMode = .rotateAuto
    anim.repeatCount = Float.infinity
    anim.path = littleCircleLayer.path
    littleRedDot.add(anim, forKey: "rotate")
}

func animateCircleExpanding() {
    let maxCircle = makeArcPath(arcCenter: containerView.bounds.center, radius: 100)
    let circleExpandingAnim = CABasicAnimation(keyPath: "path")
    circleExpandingAnim.fromValue = littleCircleLayer.path
    circleExpandingAnim.toValue = maxCircle
    circleExpandingAnim.repeatCount = Float.infinity
    circleExpandingAnim.duration = 1.5
    littleCircleLayer.add(circleExpandingAnim, forKey: "pulseCircuitAnimation")
}

这会产生以下效果:

在此处输入图片说明

但是,我想使小点沿着扩展的圆路径旋转(因为它从小圆环到大圆环动画),而不是原始的小圆环路径。有任何想法吗 ?

使用CoreAnimation根据路径为红点的位置设置动画时,假设路径没有变化。从理论上讲,您可以定义一个反映扩展圆的螺旋路径。就我个人而言,我将使用CADisplayLink,它是为屏幕刷新而优化设计的特殊计时器,并完全淘汰了CoreAnimation调用。例如

func startDisplayLink() {
    let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
    displayLink.add(to: .main, forMode: .common)
}

@objc func handleDisplayLink(_ displayLink: CADisplayLink) {
    let percent = CGFloat(displayLink.timestamp).truncatingRemainder(dividingBy: duration) / duration
    let radius = ...
    let center = containerView.bounds.center
    circleLayer.path = makeArcPath(arcCenter: center, radius: radius)
    let angle = percent * .pi * 2
    let dotCenter = CGPoint(x: center.x + cos(angle) * radius, y: center.y + sin(angle) * radius)
    redDot.path = makeArcPath(arcCenter: dotCenter, radius: 5)
}

产生:

在此处输入图片说明


完整的例子:

class ViewController: UIViewController {

    private let radiusRange: ClosedRange<CGFloat> = 10...100
    private let duration: CGFloat = 1.5

    private lazy var containerView: UIView = {
        let containerView = UIView()
        containerView.translatesAutoresizingMaskIntoConstraints = false
        return containerView
    }()

    private lazy var redDot: CAShapeLayer = {
        let layer = CAShapeLayer()
        layer.fillColor = UIColor.red.cgColor
        return layer
    }()

    private lazy var circleLayer: CAShapeLayer = {
        let layer = CAShapeLayer()
        layer.lineWidth = 1.5
        layer.strokeColor = UIColor.black.cgColor
        layer.fillColor = UIColor.clear.cgColor
        return layer
    }()

    private weak var displayLink: CADisplayLink?

    override func viewDidLoad() {
        super.viewDidLoad()

        setup()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startDisplayLink()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        stopDisplayLink()
    }
}

// MARK: Private utility methods

private extension ViewController {
    func setup() {
        addContainer()

        containerView.layer.addSublayer(circleLayer)
        containerView.layer.addSublayer(redDot)
    }

    func addContainer() {
        view.addSubview(containerView)

        NSLayoutConstraint.activate([
            containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            containerView.topAnchor.constraint(equalTo: view.topAnchor),
            containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

    func makeArcPath(arcCenter: CGPoint, radius: CGFloat) -> CGPath {
        UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
    }
}

// MARK: - DisplayLink related methods

private extension ViewController {
    func startDisplayLink() {
        stopDisplayLink()  // stop existing display link, if any

        let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
        displayLink.add(to: .main, forMode: .common)
        self.displayLink = displayLink
    }

    func stopDisplayLink() {
        displayLink?.invalidate()
    }

    @objc func handleDisplayLink(_ displayLink: CADisplayLink) {
        let percent = CGFloat(displayLink.timestamp).truncatingRemainder(dividingBy: duration) / duration
        let radius = radiusRange.percent(percent)
        let center = containerView.bounds.center
        circleLayer.path = makeArcPath(arcCenter: center, radius: radius)
        let angle = percent * .pi * 2
        let dotCenter = CGPoint(x: center.x + cos(angle) * radius, y: center.y + sin(angle) * radius)
        redDot.path = makeArcPath(arcCenter: dotCenter, radius: 5)
    }
}

// MARK: - CGRect extension

extension CGRect {
    var center: CGPoint { return CGPoint(x: midX, y: midY) }
}

// MARK: - ClosedRange extension

extension ClosedRange where Bound: FloatingPoint {
    func percent(_ percent: Bound) -> Bound {
        (upperBound - lowerBound) * percent + lowerBound
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用snap.svg沿svg路径对对象进行动画处理和定向

来自分类Dev

在Swift中对对象进行动画处理?

来自分类Dev

在Swift中对对象进行动画处理?

来自分类Dev

在React Native中对对象数组进行动画处理

来自分类Dev

沿Google Map Android中的路径对汽车(标记)进行动画处理

来自分类Dev

在屏幕外对对象进行动画处理并将其保留在那里

来自分类Dev

在多个目标属性上使用缓动函数对对象进行动画处理

来自分类Dev

在three.js中使用正弦波从其中心对对象进行动画处理

来自分类Dev

CSS对对象进行动画处理并保留其新位置

来自分类Dev

使用android加速度计数据对对象进行动画处理

来自分类Dev

在多个目标属性上使用缓动函数对对象进行动画处理

来自分类Dev

在CSS SVG动画中,我无法对Á对象进行动画处理以遵循路径

来自分类Dev

如何在Kineticjs中对曲线路径上的对象进行动画处理

来自分类Dev

iOS Swift在非线性路径中对视图进行动画处理

来自分类Dev

对圆形路径上的圆进行动画处理

来自分类Dev

在圆形路径中对GMSMarker进行动画处理

来自分类Dev

MatrixAnimationUsingPath在路径的周围(轮廓)上进行动画处理

来自分类Dev

在WPF中对路径进行动画处理

来自分类Dev

对正弦路径上的元素进行动画处理

来自分类Dev

在圆形路径中对GMSMarker进行动画处理

来自分类Dev

对Raphael元素及其发光路径集进行动画处理

来自分类Dev

在BonsaiJS中沿路径对电影进行动画处理

来自分类Dev

捕捉SVG:在路径上进行动画处理

来自分类Dev

在Swift SceneKit中使用CAKeyframeAnimation对SCN对象进行动画处理

来自分类Dev

在WPF中对大对象进行动画处理

来自分类Dev

在画布中对绘制的对象进行动画处理

来自分类Dev

用速度对svg对象列表进行动画处理

来自分类Dev

使用Swift对视图高度进行动画处理

来自分类Dev

永远对SCNNode进行动画处理-SceneKit,Swift

Related 相关文章

  1. 1

    使用snap.svg沿svg路径对对象进行动画处理和定向

  2. 2

    在Swift中对对象进行动画处理?

  3. 3

    在Swift中对对象进行动画处理?

  4. 4

    在React Native中对对象数组进行动画处理

  5. 5

    沿Google Map Android中的路径对汽车(标记)进行动画处理

  6. 6

    在屏幕外对对象进行动画处理并将其保留在那里

  7. 7

    在多个目标属性上使用缓动函数对对象进行动画处理

  8. 8

    在three.js中使用正弦波从其中心对对象进行动画处理

  9. 9

    CSS对对象进行动画处理并保留其新位置

  10. 10

    使用android加速度计数据对对象进行动画处理

  11. 11

    在多个目标属性上使用缓动函数对对象进行动画处理

  12. 12

    在CSS SVG动画中,我无法对Á对象进行动画处理以遵循路径

  13. 13

    如何在Kineticjs中对曲线路径上的对象进行动画处理

  14. 14

    iOS Swift在非线性路径中对视图进行动画处理

  15. 15

    对圆形路径上的圆进行动画处理

  16. 16

    在圆形路径中对GMSMarker进行动画处理

  17. 17

    MatrixAnimationUsingPath在路径的周围(轮廓)上进行动画处理

  18. 18

    在WPF中对路径进行动画处理

  19. 19

    对正弦路径上的元素进行动画处理

  20. 20

    在圆形路径中对GMSMarker进行动画处理

  21. 21

    对Raphael元素及其发光路径集进行动画处理

  22. 22

    在BonsaiJS中沿路径对电影进行动画处理

  23. 23

    捕捉SVG:在路径上进行动画处理

  24. 24

    在Swift SceneKit中使用CAKeyframeAnimation对SCN对象进行动画处理

  25. 25

    在WPF中对大对象进行动画处理

  26. 26

    在画布中对绘制的对象进行动画处理

  27. 27

    用速度对svg对象列表进行动画处理

  28. 28

    使用Swift对视图高度进行动画处理

  29. 29

    永远对SCNNode进行动画处理-SceneKit,Swift

热门标签

归档