UIView在UIBezierPath动画期间暂停

时间:2018-01-10 01:14:31

标签: ios swift animation uiview core-animation

我尝试使用CAKeyframeAnimation动画UIView(正方形)以沿UIBezierPath移动。方块在贝塞尔路径的两个点处暂停,两个点都在路径开始弧之前。这是我的UIBezierPath和动画的代码:

 func createTrack() -> UIBezierPath {
    let path = UIBezierPath()
    path.move(to: CGPoint(x: layerView.frame.size.width/2, y: 0.0))
    path.addLine(to: CGPoint(x: layerView.frame.size.width - 100.0, y: 0.0))
    path.addArc(withCenter: CGPoint(x: layerView.frame.size.width - 100.0,y: layerView.frame.height/2), radius: layerView.frame.size.height/2, startAngle: CGFloat(270).toRadians(), endAngle: CGFloat(90).toRadians(), clockwise: true)
    path.addLine(to: CGPoint(x:  100.0, y: layerView.frame.size.height))
    path.addArc(withCenter: CGPoint(x: 100.0,y: layerView.frame.height/2), radius: layerView.frame.size.height/2, startAngle: CGFloat(90).toRadians(), endAngle: CGFloat(270).toRadians(), clockwise: true)

    path.close()

    return path
}

@IBAction func onAnimatePath(_ sender: Any) {
    let square = UIView()
    square.frame = CGRect(x: 55, y: 300, width: 20, height: 20)
    square.backgroundColor = UIColor.red

    layerView.addSubview(square)

    let animation = CAKeyframeAnimation(keyPath: "position")

    animation.path = trackPath.cgPath

    animation.rotationMode = kCAAnimationRotateAuto
    animation.repeatCount = Float.infinity
    animation.duration = 60

    square.layer.add(animation, forKey: "animate position along path")
}

layerView只是一个UIView。关于为什么会发生这种情况以及如何解决这个问题的想法?

1 个答案:

答案 0 :(得分:2)

您使用的路径包含5个段(两个弧和三个线(包括关闭路径时的一个)),并且动画在每个段上花费相同的时间。如果此路径太窄,这些线段将没有长度,并且方块将在每个线段中显示12秒。

5 segments of the path

您可能希望使用"paced" calculation mode来获得恒定速度

animation.calculationMode = kCAAnimationPaced

这样,红色方块将以恒定的速度移动 - 无论形状的每个部分有多长。

仅此一项就可以为您提供所需的结果,但您可以采取更多措施来简化路径。

addArc(...)方法相当智能,并且会从当前点添加一条直线到弧的起点,因此不需要两条显式线。

removing the two lines

此外,如果您更改初始点,您将路径移动到具有与第二个弧的中心相同的x分量,则路径将自行关闭。在这里,你需要的只是两个弧。

only the two arcs

也就是说,如果您要创建的形状是这样的圆角矩形,那么您可以使用UIBezierPath(roundedRect:cornerRadius:)便利初始值设定项:

let radius = min(layerView.bounds.width, layerView.bounds.height) / 2.0
let path = UIBezierPath(roundedRect: layerView.bounds, cornerRadius: radius)