Как получить анимированный маршрут полилинии в GMSMapView, чтобы он перемещался вместе с картой при перемещении карты?
Я создал анимированную полилинию, такую как CAShapeLayer, следующим кодом, я добавил CAShapeLayer в качестве подуровня в GMSMapiew, но, если я перемещу карту, слой не будет перемещаться. где добавить слой, чтобы он двигался вместе с картой?
func layer(from path: GMSPath) -> CAShapeLayer {
let breizerPath = UIBezierPath()
let firstCoordinate: CLLocationCoordinate2D = path.coordinate(at: 0)
breizerPath.move(to: self.mapView.projection.point(for: firstCoordinate))
for i in 1 ..< Int((path.count())){
print(path.coordinate(at: UInt(i)))
let coordinate: CLLocationCoordinate2D = path.coordinate(at: UInt(i))
breizerPath.addLine(to: self.mapView.projection.point(for: coordinate))
}
let shapeLayer = CAShapeLayer()
shapeLayer.path = breizerPath.reversing().cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.lineWidth = 4.0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.cornerRadius = 5
return shapeLayer
}
func animatePath(_ layer: CAShapeLayer) {
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 6
//pathAnimation.delegate = self
pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
pathAnimation.fromValue = Int(0.0)
pathAnimation.toValue = Int(1.0)
pathAnimation.repeatCount = 100
layer.add(pathAnimation, forKey: "strokeEnd")
}
Добавлен в GoogleMapView
let shapelayer: CAShapeLayer = self.layer(from: path!)
self.animatePath(shapelayer)
self.mapView.layer.addSublayer(shapelayer)
![Я получаю следующий вывод]()
Ответы
Ответ 1
Я создаю анимацию GMSPath
с помощью пути coordinate
![введите описание изображения здесь]()
Цель C
интерфейс
@interface MapWithTracking ()
@property (weak, nonatomic) IBOutlet GMSMapView *mapView;
@property (nonatomic,strong) GMSMutablePath *path2;
@property (nonatomic,strong)NSMutableArray *arrayPolylineGreen;
@property (nonatomic,strong) GMSPolyline *polylineBlue;
@property (nonatomic,strong) GMSPolyline *polylineGreen;
@end
реализация
-(void)viewDidLoad {
_arrayPolylineGreen = [[NSMutableArray alloc] init];
_path2 = [[GMSMutablePath alloc]init];
}
Получите GMSPath
и создайте синюю полилинию.
-(void)createBluePolyline(GMSPath *path) {
// Here create a blue poly line
_polylineBlue = [GMSPolyline polylineWithPath:path];
_polylineBlue.strokeColor = [UIColor blueColor];
_polylineBlue.strokeWidth = 3;
_polylineBlue.map = _mapView;
// animate green path with timer
[NSTimer scheduledTimerWithTimeInterval:0.003 repeats:true block:^(NSTimer * _Nonnull timer) {
[self animate:path];
}];
}
Анимация зеленой полилинии
Добавление координаты к пути 2 и присвоение карты
-(void)animate:(GMSPath *)path {
dispatch_async(dispatch_get_main_queue(), ^{
if (i < path.count) {
[_path2 addCoordinate:[path coordinateAtIndex:i]];
_polylineGreen = [GMSPolyline polylineWithPath:_path2];
_polylineGreen.strokeColor = [UIColor greenColor];
_polylineGreen.strokeWidth = 3;
_polylineGreen.map = _mapView;
[arrayPolylineGreen addObject:_polylineGreen];
i++;
}
else {
i = 0;
_path2 = [[GMSMutablePath alloc] init];
for (GMSPolyline *line in arrayPolylineGreen) {
line.map = nil;
}
}
});
}
Ответ 2
SWIFT
Declartion
var polyline = GMSPolyline()
var animationPolyline = GMSPolyline()
var path = GMSPath()
var animationPath = GMSMutablePath()
var i: UInt = 0
var timer: Timer!
Маршрут Дарва
func drawRoute(routeDict: Dictionary<String, Any>) {
let routesArray = routeDict ["routes"] as! NSArray
if (routesArray.count > 0)
{
let routeDict = routesArray[0] as! Dictionary<String, Any>
let routeOverviewPolyline = routeDict["overview_polyline"] as! Dictionary<String, Any>
let points = routeOverviewPolyline["points"]
self.path = GMSPath.init(fromEncodedPath: points as! String)!
self.polyline.path = path
self.polyline.strokeColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
self.polyline.strokeWidth = 3.0
self.polyline.map = self.mapView
self.timer = Timer.scheduledTimer(timeInterval: 0.003, target: self, selector: #selector(animatePolylinePath), userInfo: nil, repeats: true)
}
}
Анимация пути
func animatePolylinePath() {
if (self.i < self.path.count()) {
self.animationPath.add(self.path.coordinate(at: self.i))
self.animationPolyline.path = self.animationPath
self.animationPolyline.strokeColor = UIColor.black
self.animationPolyline.strokeWidth = 3
self.animationPolyline.map = self.mapView
self.i += 1
}
else {
self.i = 0
self.animationPath = GMSMutablePath()
self.animationPolyline.map = nil
}
}
Не забывайте останавливать таймер в viewWillDisappear
self.timer.invalidate()
Выход
![введите описание изображения здесь]()
Ответ 3
Перемещение слоя всякий раз, когда карта перемещается, реализуя делегат mapView:didChangeCameraPosition:
.
Ответ 4
Это адаптация кода от Elangovan
Изменения, которые я сделал, заключались в том, чтобы удалить переменную из класса, которая должна быть только в функции, а также удалить #selector, который больше не нужен в iOS> = 10.
var timerAnimation: Timer!
var mapView:GMSMapView?
func drawRoute(encodedString: String, animated: Bool) {
if let path = GMSMutablePath(fromEncodedPath: encodedString) {
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.strokeColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
polyline.map = Singleton.shared.getMapView()
if(animated){
self.animatePolylinePath(path: path)
}
}
}
func animatePolylinePath(path: GMSMutablePath) {
var pos: UInt = 0
var animationPath = GMSMutablePath()
let animationPolyline = GMSPolyline()
self.timerAnimation = Timer.scheduledTimer(withTimeInterval: 0.003, repeats: true) { timer in
pos += 1
if(pos >= path.count()){
pos = 0
animationPath = GMSMutablePath()
animationPolyline.map = nil
}
animationPath.add(path.coordinate(at: pos))
animationPolyline.path = animationPath
animationPolyline.strokeColor = UIColor.yellow
animationPolyline.strokeWidth = 3
animationPolyline.map = self.mapView
}
}
func stopAnimatePolylinePath() {
self.timerAnimation.invalidate()
}
Ответ 5
Для этого вам нужно использовать GMSPolyline
. Создайте экземпляр GMSPolyline
, установите экземпляр GMSMapView
как родительскую карту.
GMSPolyline* routeOverlay = // config
routeOverlay.map = // my GMSMapView instance
Это все. Вам не нужно ничего делать, чтобы заставить его двигаться с движением камеры карты. Он делает это автоматически.
Ответ 6
Вы можете создать переменную для shapeLayer и использовать методы GMSMapViewDelegate: mapView (_ mapView: GMSMapView, жест willMove: Bool) и mapView (_ mapView: GMSMapView, idleAt position: GMSCameraPosition), чтобы добавить и удалить слой с карты. У этого подхода есть два недостатка: во-первых, слой не анимируется при перетаскивании (перемещении) карты, а во-вторых, слой всегда располагается поверх всех других элементов карты, таких как маркеры, названия дорог, POI и т.д. Я не смог найти способ добавить этот слой в качестве подслоя непосредственно к наземному наложению. Вы можете найти полный код ниже:
var polyLineShapeLayer:CAShapeLayer?
var layerAdded = false
var path = GMSPath()
var polyLine:GMSPolyline!
// Add regular polyline to the map
func addPolyLineWithEncodedStringInMap(_ encodedString:String) {
self.polyLine = GMSPolyline(path: self.path)
polyLine.strokeWidth = 3.8
self.polyLine.strokeColor = .black
polyLine.map = googleMapView
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.addPolyLineShapeLayerToMapView()
self.layerAdded = true
}
}
// Add CAshapeLayer to map
func layer(from path: GMSPath) -> CAShapeLayer {
let breizerPath = UIBezierPath()
let firstCoordinate: CLLocationCoordinate2D = path.coordinate(at: 0)
breizerPath.move(to: self.googleMapView.projection.point(for: firstCoordinate))
for i in 1 ..< Int((path.count())){
print(path.coordinate(at: UInt(i)))
let coordinate: CLLocationCoordinate2D = path.coordinate(at: UInt(i))
breizerPath.addLine(to: self.googleMapView.projection.point(for: coordinate))
}
let shapeLayer = CAShapeLayer()
shapeLayer.path = breizerPath.cgPath
shapeLayer.strokeColor = UIColor.lightGray.withAlphaComponent(0.8).cgColor
shapeLayer.lineWidth = 4.0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.cornerRadius = 5
return shapeLayer
}
func animatePath(_ layer: CAShapeLayer) {
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 2
pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
pathAnimation.fromValue = Int(0.0)
pathAnimation.toValue = Int(1.0)
pathAnimation.repeatCount = 200
layer.add(pathAnimation, forKey: "strokeEnd")
}
func addPolyLineShapeLayerToMapView(){
polyLineShapeLayer = self.layer(from: self.path)
if let polyLineShapeLayer = polyLineShapeLayer{
self.animatePath(polyLineShapeLayer)
self.googleMapView.layer.addSublayer(polyLineShapeLayer)
polyLineShapeLayer.zPosition = 0
}
}
// Delegate methods to control the polyline
// whenever map is about to move, if layer is already added, remove the layer from superLayer
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
if layerAdded{
DispatchQueue.main.async {
self.polyLineShapeLayer?.removeFromSuperlayer()
self.polyLineShapeLayer = nil
}
}
}
// when map is idle again(var layerAdded:bool ensures that additional layer is not added initially when the delegate method is fired) add new instance of polylineShapeLayer to the map with current projected coordinates.
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
if self.layerAdded{
self.addPolyLineShapeLayerToMapView()
}
}