How to get animated polyline route in GMSMapView, so that it move along with map when map is moved?

后端 未结 6 1360
独厮守ぢ
独厮守ぢ 2020-12-02 13:37

I have created animated polyline like CAShapeLayer by following code, I have added CAShapeLayer as sublayer to GMSMapiew but, if I move the map the layer won\'t moves. wher

相关标签:
6条回答
  • 2020-12-02 14:13

    Move the layer whenever the map moves by implementing the delegate mapView:didChangeCameraPosition:.

    0 讨论(0)
  • 2020-12-02 14:13

    This is an adaptation of the code from Elangovan

    The changes that I did was to remove the var from the class to be just in the function and also removed the #selector that is no longer need in 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()
        }
    
    0 讨论(0)
  • 2020-12-02 14:21

    You need to use GMSPolyline for this. Create a GMSPolyline instance, set your GMSMapView instance to be it's parent map.

    GMSPolyline* routeOverlay = // config
    routeOverlay.map = // my GMSMapView instance
    

    That's all. You don't need to do anything extra to make it move with the map camera movement. It does that automatically.

    0 讨论(0)
  • 2020-12-02 14:21

    You can create a variable for shapeLayer and use the GMSMapViewDelegate methods mapView(_ mapView: GMSMapView, willMove gesture: Bool) and mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) to add and remove the layer from the map. There are two downsides to this approach, first is that the layer doesn't animate when the map is being dragged(moved) and second downside is that the layer always sits on top of all other map elements like markers, road names, POIs etc. I couldn't find a way to add this layer as a sublayer directly to the ground overlay. You can find the full code below:

    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()
            }
    
        }
    
    0 讨论(0)
  • 2020-12-02 14:23

    I am create GMSPath animation with path coordinate

    Objective C

    interface

    @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
    

    implementation

    -(void)viewDidLoad {
        _arrayPolylineGreen = [[NSMutableArray alloc] init];
        _path2 = [[GMSMutablePath alloc]init];
    }
    

    Get a GMSPath and create a blue polyline.

    -(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];
           }];
    
    }
    

    Animate a Green Polyline

    Adding coordinate to path 2 and assign to map

    -(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;
                }
    
            }
        });
    }
    
    0 讨论(0)
  • 2020-12-02 14:27

    SWIFT

    Declartion

    var polyline = GMSPolyline()
    var animationPolyline = GMSPolyline()
    var path = GMSPath()
    var animationPath = GMSMutablePath()
    var i: UInt = 0
    var timer: Timer!
    

    To Darw Route

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

    To Animate Path

    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
            }
        }
    

    Don't forgot to stop timer in viewWillDisappear

    self.timer.invalidate()
    

    Output

    0 讨论(0)
提交回复
热议问题