swift - 如何在 Swift 4 中同步执行多个自定义动画函数

标签 swift animation mapkit completionhandler

我正在开发一款 IOS 应用程序,旨在帮助旅游区的人们了解交通方式。为了让他们清楚地了解如何从 A 到 B,路线通过注释对象进行了动画处理。例如,一旦用户选择查看从 A 到 D 的路线,缆车对象就会从 A 滑到 B。完成后,穿梭巴士对象会沿着道路从 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
        }

    })
}

为了沿着 map 上绘制的非线性路线(通常是道路)移动对象,我使用以下函数:

// 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)

但这并不同步执行代码。我猜它与函数中定义的时间和关键帧冲突。

我一直在搞乱自定义完成闭包,然后将每个方法放入前一个方法的完成闭包以及调度队列中。但我似乎不太理解它们,因为我无法达到预期的效果。随着路线变得更长,嵌套完成闭包似乎不是一个理想的选择,因为它们使程序变得不必要的复杂。任何建议都将受到高度赞赏。

最佳答案

我想我已经找到了问题所在。 由于animateNonLinearRoute在CALayer上触发动画,因此该函数在触发动画后返回,而无需等待其完成。因此,方法完成处理程序中的所有函数都将在 CALayer 动画被触发之后执行,而不是在它完成之后。 一个简单的 hacky 解决方案是将 CALayer 动画完成后应执行的函数包装到 CATransaction block 中:

    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 - 如何在 Swift 4 中同步执行多个自定义动画函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50448577/

相关文章:

json - 反序列化 double 组

ios - 如何在 Swift 中显示已解析的 JSON 数据?

ios - 在 Swift 中平滑展开 UIView 动画

c# - UWP 动画重置为 From 状态

wpf - XAML C# WPF 执行有序动画序列的最佳方法

ios - 使用 alamofire 下载不完整的文件

ios - SpriteKit 中的 FPS 下降

objective-c - 通过 url 设置 MKPinAnnotationView 图片

ios - 从解析加载对象并显示在 map 上

ios - MKAnnotation tap 上的 Swift/iOS MapKit 函数