Is there some method in iOS SDK for marker moving animation?

1741
1
01-19-2017 01:39 AM
ValentinCherepyanko
New Contributor
0 Kudos
1 Reply
MarkDostal
Esri Contributor

Valentin,

Thank you for your question!  While we don't have a specific method for moving a marker/graphic, it is something that can be accomplished using an AGSGraphicsOverlay and an NSTimer.  Essentially, when you want to animate a graphic, you create a repeating Timer.  When the timer fires, you can update the geometry of the graphic.

Below is a simple view controller (written in Swift 3) that displays a map view with a map and a single graphic.  When you tap on the screen, the graphic will start animating toward the tapped point.  When it reaches the taped point, it will stop.  However, if you tap again before the animation finished, the graphic will start animating towards the new tapped point.

//

//  AnimatingGraphicViewController.swift

//

//  Created by Mark Dostal on 1/25/17.

//

//

import UIKit

class AnimatingGraphicViewController: UIViewController, AGSGeoViewTouchDelegate {

    

    var mapView : AGSMapView = AGSMapView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

    var graphic = AGSGraphic()

    var moveToPoint:AGSPoint?

    var timer = Timer()

    var dx:Double = 0.0

    var dy:Double = 0.0

    let fireCountMax:Int = 20  //the maximum number of times we want the timer to fire

    var fireCount:Int = 0

    let timerDuration:Double = 2 //duration in seconds for the animation

    override func viewDidLoad() {

        super.viewDidLoad()

        // add map view

        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        mapView.frame = view.bounds

        view.addSubview(mapView)

        //set the mapView's touchDelegate so we get touch events

        mapView.touchDelegate = self

        

        //create the map

        let map = AGSMap(basemap: AGSBasemap.darkGrayCanvasVector())

        mapView.map = map

        

        map.load{ error in

            //check for map load error and display if necessary

            if let error = error{

                let alert = UIAlertController(title: "Error Loading Map", message: error.localizedDescription, preferredStyle: .alert)

                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))

                self.present(alert, animated: true, completion: nil)

            }

            else {

                //create graphics overlay

                let animationGraphicsOverlay = AGSGraphicsOverlay()

                //create point geometry and graphic and add the graphic to our animationGraphicsOverlay

                let point = AGSPoint(x: 0, y: 0, spatialReference: map.spatialReference)

                self.graphic = AGSGraphic(geometry: point, symbol: AGSSimpleMarkerSymbol(style: .circle, color: UIColor.red, size: 24), attributes: nil)

                animationGraphicsOverlay.graphics.add(self.graphic)

                

                //add our overlay to the map and make it visible

                self.mapView.graphicsOverlays.add(animationGraphicsOverlay)

                animationGraphicsOverlay.isVisible = true

            }

        }

    }

    func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {

        

        //get the current point from the graphic and calculate how far we want it

        //to move in each direction

        if let currentPoint = graphic.geometry as? AGSPoint {

            dx = (mapPoint.x - currentPoint.x) / Double(fireCountMax)

            dy = (mapPoint.y - currentPoint.y) / Double(fireCountMax)

        }

        

        //set our moveTo point:

        moveToPoint = mapPoint

        

        //stop the old timer and remove it from the run loop

        timer.invalidate()

        

        //reset the fire count and create and start a new timer

        fireCount = 0

        timer = Timer.scheduledTimer(timeInterval: timerDuration / Double(fireCountMax),

                                     target:self,

                                     selector: #selector(moveGraphic),

                                     userInfo: nil,

                                     repeats: true)

    }

    

    func moveGraphic(_ timer: Timer) {

        

        if fireCount < fireCountMax {

            //calculate the new geometry and set it on the graphic

            if let currentPoint = graphic.geometry as? AGSPoint {

                self.graphic.geometry = AGSPoint(x: currentPoint.x + dx, y: currentPoint.y + dy, spatialReference: currentPoint.spatialReference)

            }

            fireCount = fireCount + 1

        }

        else {

            //timer reach the fireCount, move to final location (moveToPoint)

            //to make sure we're at the correct spot

            self.graphic.geometry = moveToPoint

            timer.invalidate()

        }

    }

}

0 Kudos