Posted onEdited onDisqus: Word count in article: 4.7kReading time ≈4 mins.
In June this year, while attending WWDC in San Jose, I saw this loading animation when using Uber to meet friends at Cupertino Library.
The animation was awesome!
I was curious about how they did it, so I did some exploration.
Preview
Well, the line animation still isnβt smooth enough. Does anyone have any better ideas?
Step by Step
Rotating the Map
For the following two reasons, I chose ο£ΏMap to be the default map for demonstration:
After WWDC19, the Simulator is built on top of the Meta and Core layers of MapKit, which utilize the GPU of the underlying Mac system.
Google Maps requires developer keys for access, which means you canβt directly run it on the simulator after forking the repository on GitHub.
ο£Ώ You can adjust the map interactions by embedding them in a UIView.animate block.
1 2 3 4 5 6 7 8
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseInOut, animations: { [weakself] in self?.mapView.setCamera(MKMapCamera(lookingAtCenter: center, fromDistance: fromDistance, pitch: pitch, heading: 0), animated: true) }) { b in self.pinAnimation() UIView.animate(withDuration: 180, delay: 0, options: [.curveLinear, .autoreverse], animations: { [weakself] in self?.mapView.setCamera(MKMapCamera(lookingAtCenter: center, fromDistance: fromDistance, pitch: pitch, heading: heading), animated: true) }, completion: nil) }
Google Maps must use CATransaction.
1 2 3 4
CATransaction.begin() CATransaction.setValue(NSNumber(float: 1.0), forKey: kCATransactionAnimationDuration) // change the camera, set the zoom, whatever. CATransaction.commit()
Pin Animation
We need two CAShapeLayer to create the animation, one for the circle and one for the pin. Note that the circle disappears once it reaches the maximum value, and the pin has an easeIn curve.
let currentSegment =MKPolyline(coordinates: subCoordinates, count: subCoordinates.count) self.mapView.addOverlay(currentSegment)
Animating the Polyline
This is the tricky part.
When we see that the Uber animation is close enough, the polyline is drawn on the map by rotating it.
What I need to do is continue adding and removing polylines on the map to simulate animation. Similarly, when it reaches the start and end of the pin, the line has a head and a tail.
if currentStep > totalSteps { timer.invalidate() return }
let start = currentStep-delta <0?0 : currentStep-delta let end = currentStep > route.count ? route.count : currentStep
let subCoordinates =Array(route[start..<end]) let currentSegment =MKPolyline(coordinates: subCoordinates, count: subCoordinates.count) self.mapView.addOverlay(currentSegment)