代码之家  ›  专栏  ›  技术社区  ›  rv7284

在循环路径上设置层动画

  •  1
  • rv7284  · 技术社区  · 7 年前

    我想动画我的拇指层上绘制的路径。我可以根据值设置进度层的动画,但是移动整个层不起作用。

    enter image description here

    func setProgress(_ value:Double, _ animated :Bool) {
        let progressAnimation = CABasicAnimation(keyPath: "strokeEnd")
        progressAnimation.duration = animated ? 0.6 : 0.0
        progressAnimation.fromValue = currentValue
        progressAnimation.toValue = value
        progressAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        progressLayer.strokeEnd = CGFloat(value)
        progressLayer.add(progressAnimation, forKey: "animateprogress")
    }
    

    使用这个功能,我可以动画的进展层。我被困在动画拇指位置。

    我试过一些方法,但没用。

    尝试1失败

        guard let path = thumbLayer.path else {return}
        let center = CGPoint(x: frame.width/2, y: frame.height/2)
        let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
        let thumbAngle = 2 * .pi * currentValue - (.pi/2)
        let thumbX = CGFloat(cos(thumbAngle)) * radius
        let thumbY = CGFloat(sin(thumbAngle)) * radius
        let newThumbCenter = CGPoint(x: center.x + thumbX, y: center.y + thumbY)
        let thumbPath = UIBezierPath(arcCenter: newThumbCenter, radius: thumbWidth/2, startAngle: -.pi/2, endAngle: .pi*1.5, clockwise: true)
    
        let thumbAnimation = CABasicAnimation(keyPath: "path")
        thumbAnimation.duration = animated ? 0.6 : 0.0
        thumbAnimation.fromValue = path
        thumbAnimation.toValue = thumbPath.cgPath
        thumbAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        thumbLayer.strokeEnd = CGFloat(value)
        thumbLayer.add(thumbAnimation, forKey: "animateprogress")
    

    尝试2失败

        let intialPosition = thumbLayer.position
        let center = CGPoint(x: frame.width/2, y: frame.height/2)
        let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
        let thumbAngle = 2 * .pi * currentValue - (.pi/2)
        let thumbX = CGFloat(cos(thumbAngle)) * radius
        let thumbY = CGFloat(sin(thumbAngle)) * radius
        let newThumbCenter = CGPoint(x: center.x + thumbX - thumbCenter.x, y: center.y + thumbY - thumbCenter.y)
    
        thumbLayer.position.x = newThumbCenter.x
        let thumbAnimationX = CABasicAnimation(keyPath: "progress.x")
        thumbAnimationX.duration = animated ? 0.6 : 0.0
        thumbAnimationX.fromValue = intialPosition.x
        thumbAnimationX.toValue = newThumbCenter.x
        thumbAnimationX.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        thumbLayer.add(thumbAnimationX, forKey: "progress.x")
    
    
        thumbLayer.position.y = newThumbCenter.y
        let thumbAnimationY = CABasicAnimation(keyPath: "progress.y")
        thumbAnimationY.duration = animated ? 0.6 : 0.0
        thumbAnimationY.fromValue = intialPosition.y
        thumbAnimationY.toValue = newThumbCenter.y
        thumbAnimationY.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        thumbLayer.add(thumbAnimationY, forKey: "progress.y")
    
    1 回复  |  直到 7 年前
        1
  •  10
  •   rob mayoff    7 年前

    position 属于 thumbLayer (但是设置了错误的关键点路径的动画)。

    既然这两种方法都难以奏效,那就换一种方法吧。看看标准 Swiss railway clock :

    Swiss railway clock

    这就是我们要做的,但我们不会画出全部的二手货。我们就在最后画一个红点。

    拇指层 的坐标系位于圆形轨迹的中心,我们将设置其路径,以便拇指出现在路径上。布局如下:

    layout

    下面是设置 circleLayer 和一个 拇指层

        private let circleLayer = CAShapeLayer()
        private let thumbLayer = CAShapeLayer()
    
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
    
            let circleRadius: CGFloat = 100
            let thumbRadius: CGFloat = 22
            let circleCenter = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    
            circleLayer.fillColor = nil
            circleLayer.strokeColor = UIColor.black.cgColor
            circleLayer.lineWidth = 4
            circleLayer.lineJoin = .round
            circleLayer.path = CGPath(ellipseIn: CGRect(x: -circleRadius, y: -circleRadius, width: 2 * circleRadius, height: 2 * circleRadius), transform: nil)
            circleLayer.position = circleCenter
            view.layer.addSublayer(circleLayer)
    
            thumbLayer.fillColor = UIColor.red.cgColor
            thumbLayer.strokeColor = nil
            thumbLayer.path = CGPath(ellipseIn: CGRect(x: -thumbRadius, y: -circleRadius - thumbRadius, width: 2 * thumbRadius, height: 2 * thumbRadius), transform: nil)
            thumbLayer.position = circleCenter
            view.layer.addSublayer(thumbLayer)
        }
    

    使用这种布局,我们可以沿着轨迹移动拇指而不改变其位置。相反,我们轮换 围绕其起源:

        @IBAction func buttonWasTapped() {
            let animation = CABasicAnimation(keyPath: "transform.rotation")
            animation.fromValue = 0
            animation.toValue = 2 * CGFloat.pi
            animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            animation.duration = 1.5
            animation.isAdditive = true
            thumbLayer.add(animation, forKey: nil)
        }
    

    结果:

    demo

    推荐文章