我想为绘制的路径上的拇指层设置动画。我可以根据该值对进度层进行动画处理,但是移动整个层是行不通的。
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")
答案 0 :(得分:7)
在您的第一次尝试中,您试图为拇指的路径(红色圆圈的轮廓)设置动画。第二次尝试是为position
中的thumbLayer
设置动画(但您设置了错误的关键路径动画)。
由于您在进行任何一项工作时都遇到困难,因此让我们尝试另一种方法。看看标准的Swiss railway clock:
具体来说,请看秒针末端的红点。时钟如何在脸上移动红点?通过绕着脸部中心旋转秒针。
这就是我们要做的,但是我们不会抽整张秒针。我们将在最后画一个红点。
我们将thumbLayer
的坐标系的原点放置在圆形轨迹的中心,并设置其路径,以使拇指出现在路径上。这是布局:
这里是设置circleLayer
和thumbLayer
的代码:
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)
}
使用此布局,我们可以沿轨迹移动拇指而无需更改其位置。相反,我们绕其原点旋转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)
}
结果: