How to remove "trace" of a mark in swift - ios

I'm working on a tracker app and I managed to pull some data from the server and update other user's so called track. But I have this mark .person, which appears on every step. How Should I remove it?
Polyline is drawn like this:
private func updateOnlineTrackOnMap() {
let locations = self.track?.points?.map { $0.location } ?? []
guard locations.count >= 2 else { return }
mapView.drawPolyline(withLocations: locations)
mapView.setMark(.person, to: locations.last!.coordinate)
}
But mapView.removeMark(.person) doesn't work.

Ok, there were some custom methods. I've managed to do the trick like so:
if let oldAnnotation = self.drawer.oldAnnotation {
mapView.removeAnnotation(oldAnnotation)
}
let annotation = MKPointAnnotation()
annotation.coordinate = locations.last!.coordinate
annotation.title = "Speed"
let speed = locations.last!.speed * 3.6
annotation.subtitle = String(format: "%.2f km/h", speed)
mapView.addAnnotation(annotation)
mapView.selectAnnotation(annotation, animated: false)
oldAnnotation = annotation
mapView.drawPolyline(withLocations: locations)
There's just a global variable to store current annotation coordinate. And then in mapView :viewFor: I wrote something like this:
if annotation is MKPointAnnotation {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "Online")
annotationView.image = rotatedArrow
annotationView.canShowCallout = true
return annotationView
}

Related

Is there a preset 'index' or something similar that allows me to refer to specific annotations that a user created? Swift 4

I have an app where the user can search for locations, tap on the row in the table view, and an annotation will be placed at the placemark. I have a button, "meetUpButton" that allows them to put multiple annotations, rather than what my code does by default which is remove the annotation if a new search result is clicked. Is there a way to refer to a specific annotation that my user created, even if they made multiple? For example, say I want to add the latitude of two annotations that my user created...
If I have
let annotation = MKPointAnnotation()
annotation.coordinate.latitude
Is there a way to refer to something like the first annotation with an index of 0 and the next one that my user chose with a 1 or another way? Here's some of my code which might make this clearer.
extension ViewController: handleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark) {
resultSearchController?.isActive = false
// cache the pin
selectedPin = placemark
// clear existing pins
if meetUpOutlet.isEnabled == true {
mapView.removeAnnotations(mapView.annotations)
} else {
}
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let state = placemark.administrativeArea {
annotation.subtitle = "(\(city)) (\(state))"
}
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
}
}
You can try to use annotations property of MKMapView instance , to get all use
let anns = self.mapView.annotations
You can implement Custom annotation class.
e.g.
class MyAnnotation : NSObject, MKAnnotation {
var coordinate : CLLocationCoordinate2D
var title: String?
var subtitle: String?
var index: Int?
init(location coord:CLLocationCoordinate2D) {
self.coordinate = coord
super.init()
}
}
Usage:
let annotation = MyAnnotation(location: coordinate)
annotation.title = "title"
annotation.subtitle = "subtitle"
annotation.index = 1
Remove annotations (only index == 1)
for annotation in self.mapView.annotations {
guard let annotation = annotation as? MyAnnotation else {
continue
}
if annotation.index == 1 {
self.mapView.removeAnnotation(annotation)
}
}

Pin correct Annotation Image parse backend

I have setup a map in which data is loaded from the parse backend. In map I want to display the images that are already saved in Assets folder. Image should be equal to Player Name . There latitude and longitude is already saved in the Parse.
The position of the player is displayed correctly but the image is not being showed correctly , if the last name in the playerName column is Sachin then the image is same for all the player annotation pin.
I want to apply like if playerName == annotation.title the image of rahul should be displayed .
Console Print :
26.6481591686873 , 77.1777485870544 Sachin
27.655116868732 , 77.17778705437 Rahul
28.6479996556687 , 77.1779252453013 Matt
28.6480628887157 , 77.1779590059193 Virat
28.1578689896 , 76.989079 Sachin
var playerName:String!
override func viewDidLoad() {
super.viewDidLoad()
query.findObjectsInBackgroundWithBlock { (posts, error) in
if error == nil {
let myPosts = posts! as [PFObject]
for posts in myPosts {
let latitude12 = posts["playerLat"] as! Double
let longitude12 = posts["playerLong"] as! Double
let playName = posts["playerName"] as! String
self.playerName = posts["playerName"] as! String
print(latitude12,"," , longitude12, playerName)
let annotation = MKPointAnnotation()
//let customAnno = MKAnnotationView()
let locationCoordinate = CLLocationCoordinate2DMake(latitude12, longitude12)
annotation.coordinate = locationCoordinate
//customAnno.enabled = true
let anno = self.mapView.dequeueReusableAnnotationViewWithIdentifier("places")
if anno == nil {
// if annotation.title == "Sachin" {
//}
annotation.title = playerName
self.mapView.addAnnotations([annotation])
} else {
anno?.annotation = annotation
}
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "customAnnotationView"
let annotation1 = MKPointAnnotation()
// custom image annotation
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if (annotationView == nil) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
else {
annotationView!.annotation = annotation
}
if annotation1.title == "Rahul" {
annotationView!.image = UIImage(named: "Rahul")}
else if annotation1.title == "Sachin"{
annotationView!.image = UIImage(named: "Sachin")
}
return annotationView
}
I have tried all codes but the image is same for all the players image.

Attempting to change MKAnnotation color within my code?

So I have set up my MKAnnotations in MapView and it's working as I want it to. Now I would like to experiment further and try to change the colors of the pins, what would be the most efficient way to implement this within the following code:
override func viewDidAppear(animated: Bool) {
var annotationQuery = PFQuery(className: "Post")
currentLoc = PFGeoPoint(location: MapViewLocationManager.location)
//annotationQuery.whereKey("Location", nearGeoPoint: currentLoc, withinMiles: 10)
annotationQuery.whereKeyExists("Location")
annotationQuery.findObjectsInBackgroundWithBlock {
(points, error) -> Void in
if error == nil {
// The find succeeded.
println("Successful query for annotations")
// Do something with the found objects
let myPosts = points as! [PFObject]
for post in myPosts {
let point = post["Location"] as! PFGeoPoint
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
annotation.title = post["title"] as! String!
annotation.subtitle = post["username"] as! String!
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.pinColor = .Green
return pinView
}
self.mapView.addAnnotation(annotation)
}
} else {
// Log details of the failure
println("Error: \(error)")
}
}
I can't seem to tackle this on my own even though it seem's simple enough. I am also confused about the viewForAnnotation method, from what I could gather it seems like i need to use it, but nothing i'm trying is working.
I know this is a late answer but for anyone else searching, check out the tutorial here which shows exactly how to colour pins
Ray Wenderlich MapView

Swift - setting different images from array to annotation pins

I wonder how to set different images to annotation pins on mapview. The difference between the following questions
viewForAnnotation confusion and customizing the pinColor iteratively
Swift different images for Annotation
is that my array of images is generated dynamically with regard to server response. There is no fixed size of the array, so switch/case construction is not a good idea. Moreover, I'm not sure how to apply the solution with custom class aforementioned in topic above. I'm aware that it would be better to post a comment to one of the questions asked before, but unfortunately I'm too rookie at the moment to do that(too few points).
This is the for loop performed inside functions that shows map:
for var r=0;r<arrayOfRestaurants.count;r++
{
var summonRestaurant:NSDictionary = arrayOfRestaurants[r] as NSDictionary
var nearbyRestaurant = Restaurant(nearbyRestaurants:summonRestaurant)
var latRestaurant=(nearbyRestaurant.latitude as NSString).doubleValue
var longRestaurant=(nearbyRestaurant.longitude as NSString).doubleValue
var locationOfRestaurant = CLLocationCoordinate2D(
latitude: latRestaurant as CLLocationDegrees, longitude: longRestaurant as CLLocationDegrees)
var lunchArray: NSArray = nearbyRestaurant.lunch as NSArray
var annotation = MKPointAnnotation()
annotation.setCoordinate(locationOfRestaurant)
annotation.title = nearbyRestaurant.name + " " + nearbyRestaurant.distance + " km"
map.addAnnotation(annotation)
}
And here is viewForAnnotation delegate method(quite identical to the method used in aforementioned threads):
func mapView(map: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = map.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.pinColor = .Purple
pinView!.image = globalImageArray[0]
}
else {
pinView!.annotation = annotation
}
return pinView
}
As you can see, I assigned a certain image to pinView which is globalImageArray[0], but I look for a solution that let me iterate over the globalImageArray and assign a certain image to each pin.
I'd be glad to receive any help, thanks in advance!
First, you need to create your own class that adopts the MKAnnotation protocol for your annotations -
class RestaurantAnnotation : NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String
var subtitle: String
var image: UIImage?
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
Then, use instances of this class when you add the annotation and set the image -
for var r=0;r<arrayOfRestaurants.count;r++
{
var summonRestaurant:NSDictionary = arrayOfRestaurants[r] as NSDictionary
var nearbyRestaurant = Restaurant(nearbyRestaurants:summonRestaurant)
var latRestaurant=(nearbyRestaurant.latitude as NSString).doubleValue
var longRestaurant=(nearbyRestaurant.longitude as NSString).doubleValue
let locationOfRestaurant = CLLocationCoordinate2D(
latitude: latRestaurant as CLLocationDegrees, longitude: longRestaurant as CLLocationDegrees)
var lunchArray: NSArray = nearbyRestaurant.lunch as NSArray
let title = nearbyRestaurant.name + " " + nearbyRestaurant.distance +" km"
var annotation = RestaurantAnnotation(coordinate, title:title, subtitle:"")
annotation.image = globalImageArray[r]
map.addAnnotation(annotation)
}
Now, in your view for annotation you can access the image -
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if !(annotation is RestaurantAnnotation) {
return nil
}
let reuseId = "restaurant"
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.canShowCallout = true
}
else {
anView.annotation = annotation
}
let restaurantAnnotation = annotation as RestaurantAnnotation
if (restaurantAnnotation.image != nil) {
anView.image = restaurantAnnotation.image!
anView.image.layer.setCornerRadius(8.0)
anView.image.layer.clipsToBounds=true
}
else {
// Perhaps set some default image
}
return anView
}

I can't seem to set the MKMapView annotation title after the first time it has been set

What happens is I type in an address in the search field and click go. The location is found and the map zooms in. I click on the pin image and the title bubble pops up and shows the title.
I created a property "pin" to be a reference to the title property. After dragging to a new location has completed I set the property title label using the reference to the new location. In NSLog the property is showing as changed. But when I tap drag to a new location and dragging has ended the same original value of the title property remains unchanged.
I've looked at tons of questions about similar things and nothing is working.
Here is my GO button method:
#IBAction func didTapGoButton(sender: UIButton) {
self.spinnerContainer.hidden = false
var geocoder = CLGeocoder()
geocoder.geocodeAddressString(searchField.text, {(placemarks: [AnyObject]!, error: NSError!) -> Void in
if let placemark = placemarks?[0] as? CLPlacemark {
var region = self.mapView.region as MKCoordinateRegion
region.center = placemark.location.coordinate
region.span.longitudeDelta = 0.0144927536
region.span.latitudeDelta = 0.0144927536
self.mapView.zoomEnabled = true
self.mapView.scrollEnabled = true
let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = "\(placemark.name), \(placemark.locality), \(placemark.country)"
self.spinnerContainer.hidden = true
self.mapView.addAnnotation(pa)
self.pin = pa
self.mapView.setRegion(region, animated: true)
self.annotationTitle = pa.title
self.searchField.text = ""
//self.mapView.selectAnnotation(pa, animated: true)
var newLocation = CLLocation(latitude: pa.coordinate.latitude, longitude: pa.coordinate.longitude)
var geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks: [AnyObject]!, error: NSError!) -> Void in
if let placemark = placemarks?[0] as? CLPlacemark {
// let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = "\(placemark.name), \(placemark.locality), \(placemark.administrativeArea), \(placemark.country), \(placemark.postalCode)"
NSLog("\(pa.title)")
self.addressFromCoordinates.text = pa.title
self.noAddressLabel.hidden = true
}
})
}
})
}
My viewForAnimation:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
let reuseId = "pin"
var pin = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if pin == nil {
NSLog("PIN NIL")
pin = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pin.image = UIImage(named: "pin")
pin.draggable = true
pin.canShowCallout = true
}
else
{
NSLog("PIN NOT NIL")
pin.annotation = annotation
}
return pin;
}
my didChangeDragState method:
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.Starting
{
view.dragState = MKAnnotationViewDragState.Dragging
}
else if newState == MKAnnotationViewDragState.Ending || newState == MKAnnotationViewDragState.Canceling
{
view.dragState = MKAnnotationViewDragState.None
var newLocation = CLLocation(latitude: self.pin.coordinate.latitude, longitude: self.pin.coordinate.longitude)
var geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks: [AnyObject]!, error: NSError!) -> Void in
if let placemark = placemarks?[0] as? CLPlacemark {
let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = "\(placemark.name), \(placemark.locality), \(placemark.administrativeArea), \(placemark.country), \(placemark.postalCode)"
self.annotationTitle = pa.title
self.addressFromCoordinates.text = pa.title
self.editAddressButton.hidden = false
self.noAddressLabel.hidden = true
}
})
NSLog("\(self.pin.coordinate.latitude), \(self.pin.coordinate.longitude)")
}
}
Is there some sort of refresh that needs to be done to the map view after dragging?
Thanks for your time
In didChangeDragState, this code:
let pa = MKPointAnnotation()
pa.coordinate = placemark.location.coordinate
pa.title = "\(placemark.name), \(placemark.locality), \(placemark.administrativeArea), \(placemark.country), \(placemark.postalCode)"
self.annotationTitle = pa.title
is not updating the title of the annotation just dragged because:
The pa in pa.title = ... is referring to a new instance of MKPointAnnotation which is not connected in any way to the annotation just dragged. The let pa = MKPointAnnotation() line creates a new instance of an MKPointAnnotation. This new instance just exists locally in memory and is not even added to the map.
The update to self.annotationTitle has no effect on the title of the annotation instance that was just dragged because annotationTitle is just some separate string variable you've declared and the original MKPointAnnotation that was added to the map and just dragged has no knowledge or connection whatsoever with annotationTitle (the fact that annotationTitle was initially set equal to the annotation's title in the didTapGoButton does not somehow "link" the two strings together).
In didTapGoButton, you are saving a reference to the annotation object that is actually added (and then dragged) in the pin variable. This pin variable is the reference you can use to update the title of the annotation that was dragged (assuming you will only have one annotation at a time).
So in didChangeDragState, change the code shown above to:
self.pin.coordinate = placemark.location.coordinate
self.pin.title = "\(placemark.name), \(placemark.locality), \(placemark.administrativeArea), \(placemark.country), \(placemark.postalCode)"
self.annotationTitle = self.pin.title
However, for your requirements, note that it's not really necessary to keep your own reference to the annotation in the first place...
In didChangeDragState, you can get access to the annotation that was dragged directly from the view argument that is passed into the method. For example:
let ann = view.annotation as MKPointAnnotation
ann.coordinate = placemark.location.coordinate
ann.title = "\(placemark.name), \(placemark.locality), \(placemark.administrativeArea), \(placemark.country), \(placemark.postalCode)"
self.annotationTitle = ann.title
Side Note:
After dragging the annotation and reverse geocoding the new location, there is a good possibility that the geocoded coordinates will be different than where the user dragged the annotation to. This happens because the nearest geocoded address may be slightly further from where the annotation was dragged to. So what will happen is the annotation will move a bit after the user finishes dragging. If you'd rather keep the annotation exactly where the user dragged it, don't update the annotation's coordinate in the geocoder's completion block and only update the title. You may want to set the title to something like "near xyz" if the geocoded address is X meters or more away from the actual coordinates.

Resources