我正在制作一个IOS应用程序,旨在帮助旅游区的人们了解交通工具。为了让他们清楚地了解如何从A到B,使用Annotation对象对路径进行动画处理。例如,一旦用户选择查看从A到D的路线,则缆车对象从A滑动到B.一旦完成,Shuttle Bus对象沿着从B到C的道路移动,然后船从C滑动到d。
所以我编写了以下函数。 这个让transportMode对象(小船,缆车等的小图像)从A到B或B到A的直线滑动。
func animateLinearRoute(transportMode: TransportAnnot, startcoor:
CLLocationCoordinate2D, destcoor: CLLocationCoordinate2D){
UIView.animate(withDuration: 3, animations:
{
if (transportMode.coordinate.latitude == startcoor.latitude && transportMode.coordinate.longitude == startcoor.longitude) {
transportMode.coordinate = destcoor
} else {
transportMode.coordinate = startcoor
}
})
}
为了沿着地图上绘制的非线性路线(通常是道路)移动物体,我使用以下功能:
// pass mode of transport and coordinates along the travel route
func animateNonLinearRoute(transportMode: TransportAnnot, animroute: [CLLocationCoordinate2D]){
let path = UIBezierPath()
// get start point of route from coordinates and start drawing route
let point = self.mapView.convert(animroute[0], toPointTo: self.mapView)
path.move(to: point)
// translate each coordinate along the route into a point in the view for drawing
for coor in animroute {
let point = self.mapView.convert(coor, toPointTo: self.mapView)
path.addLine(to: point)
}
// create keyframe animation to move annotation along the previously drawn path
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path.cgPath
animation.duration = 5.0
animation.isRemovedOnCompletion = false
let transportview = self.mapView.view(for: transportMode)
transportview?.layer.add(animation, forKey: "animate position along path")
transportMode.coordinate = animroute[animroute.count - 1]
CATransaction.commit()
}
现在,完整路线可以包含这些方法的任意链。例如,用户可以选择到达需要线性路线的点 - >非线性路线 - >线性路线 - >非线性 - >非线性的。
最终动画需要以严格连续的方式执行,这样用户就不会感到困惑(第二个动画不应该开始,除非第一个动画完成,等等。)
一个考虑因素是像这样的关键帧动画:
UIView.animateKeyframes(withDuration: 8, delay: 0, options: .calculationModeLinear, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 5/8, animations: {
self.animateNonLinearRoute(transportMode: self.bus, animroute: self.br.coordinates)
})
UIView.addKeyframe(withRelativeStartTime: 5/8, relativeDuration: 3/8, animations: {
self.animateLinearRoute(transportMode: self.cableCar, startcoor: self.lowerstation, destcoor: self.midstation)
})
// dynamically fill up as needed using appropriate relative start times and durations
}, completion: nil)
虽然不会同步执行代码。我猜它与函数中定义的时间和关键帧冲突。
我一直在搞乱自定义完成闭包,然后将每个方法放在前一个方法的完成闭包中以及调度队列中。但我似乎并不理解它们,因为我无法达到预期的效果。并且随着路径变得更长,嵌套完成闭包似乎不是理想的选择,因为它们使程序不必要地复杂化。任何建议都非常感谢。
答案 0 :(得分:0)
我想我追查了这个问题。 由于animateNonLinearRoute在CALayer上触发动画,因此该函数在触发动画后返回,而不等待其完成。因此,在完成CALayer动画之后,方法完成处理程序中的所有函数都将被执行,而不是在它完成之后。 一个简单的hacky解决方案是将CALayer动画完成后应该执行的函数包装到CATransaction块中:
CATransaction.begin()
CATransaction.setCompletionBlock({
self.animateLinearRoute(transportMode: self.cableCar, startcoor: self.lowerstation, destcoor: self.midstation)
})
self.animateNonLinearRoute(transportMode: self.bus, animroute: self.br.coordinates)
CATransaction.commit()
我很想听听Swift中多线程和并发的理解的更好的解释,以及一个链接其中几个函数调用的干净方法的建议。