如何在 Swift 4 中同步执行多个自定义动画函数
Posted
技术标签:
【中文标题】如何在 Swift 4 中同步执行多个自定义动画函数【英文标题】:How to execute multiple custom animation functions synchronously in Swift 4 【发布时间】:2018-05-21 12:07:41 【问题描述】:我正在开发一个 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)
虽然这不会同步执行代码。我猜它与函数中定义的时间和关键帧有冲突。
我一直在搞乱自定义完成闭包,然后将每个方法放入前一个的完成闭包以及调度队列中。但我似乎并不真正理解它们,因为我无法达到预期的效果。并且随着路由变得更长,嵌套的完成闭包似乎不是一个理想的选择,因为它们使程序变得不必要地复杂。任何建议都非常感谢。
【问题讨论】:
【参考方案1】:我想我找到了问题所在。 由于 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 中的多线程和并发的人那里听到更好的解释,以及对链接其中几个函数调用的简洁方法的建议。
【讨论】:
以上是关于如何在 Swift 4 中同步执行多个自定义动画函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在swift ios中的自定义TableView单元格中显示多个字符串值到多个标签?
iOS - 如何在没有第三方框架的情况下在 Swift 中创建自定义动画横幅