Can we get all the annotation views from MKMapView - iphone

Is there any direct method or any suggestion on how to get all the annotations from the MKMapView?

You can access map's annotations using its annotations property. Getting views for all annotations may not be always possible as annotations that are not currently visible on the map may have no views associated with them, but for arbitrary annotation you can try to get a view using -viewForAnnotation: method.
So here how you can iterate through all map's annotations and try to access their views:
for (id<MKAnnotation> annotation in mapView.annotations){
MKAnnotationView* anView = [mapView viewForAnnotation: annotation];
if (anView){
// Process annotation view
...
}
}

In swift 3.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
let selectedAnnotation = view.annotation
for annotation in mapView.annotations {
let viewI = mapView.view(for: annotation)
if !(viewI?.annotation is MKUserLocation){
if annotation.isEqual(selectedAnnotation) {
viewI?.image = UIImage(named: "focus.png")
showLifeEventView(anotation: view) //did select a point on Map.
}else{
viewI?.image = UIImage(named: "point.png")
}
}
}
}

Related

SwiftUI MapKit - Multiple annotations in same map

I've had a look at similar questions but nothing seems to answer this question exactly.
I have a Map view and I want to add pin overlays, as well as a poly line route overlay on top of it. I am very very new at SwiftUI dev (this is my first app), so some help would be appreciated.
At the moment the map only renders the pins, and not the overlay. I'm assuming they need to be put into the same method but cannot figure out how you can return multiple overlays to the mapView.
Here is the Coordinator code:
class Coordinator: NSObject,MKMapViewDelegate{
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
//draw pins
if annotation.isKind(of: MKUserLocation.self){return nil}
else{
let pinAnnotation = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "PIN_VIEW")
pinAnnotation.tintColor = .red
pinAnnotation.animatesDrop = true
pinAnnotation.canShowCallout = true
return pinAnnotation
}
}
private func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKPolylineRenderer? {
//draw route
let render = MKPolylineRenderer(overlay: overlay)
render.strokeColor = .orange
render.lineWidth = 2
return render;
}
}
Here is the output: (no route is drawn). I tried to put the annotations within the same method but couldn't figure out how to return both at the same time (pins are of type MKAnnotationView and the route is of type MKPolylineRenderer...
Help would be really appreciated. Thanks
It should be a separate method, but it shouldn’t be private. Also, the return type should be MKOverlayRenderer.

Calling mapView(_:viewFor:) when user location changes

I want to have the user location being shown as a custom image (not the blue beacon). I also want that whenever the user location changes its coordinates, this custom image is rotated accordingly to represent the user course. In order to achieve that, I implemented the code below. It is being called with annotation type userLocation when the app is started, so that the user location custom image is being shown fine. The problem is that when I simulate a change in user location coordinates, the delegate mapView(_:viewFor:) method is never called again with an annotation type userLocation, so the image is never rotated. (Note: the UIImage rotateImage(by:) is a custom method).
Is there some means to call mapView(_:viewFor:) so that I can update the image annotation for user location when user location changes? Thanks for any help.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isEqual(mapView.userLocation) {
// Annotation image for user location
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.image = UIImage(named: "UserLocationImage.png")?.rotateImage(by: currentCourse)
return annotationView
}
}
Use CLLocationManagerDelegate
https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate
Implement this protocol in your code, and put your mapView function into its locationManager(_:didUpdateLocations:) method.

Implementing gesture on a marker.iconView in swift 3 and google maps for ios

I've got a google map and i'm setting marker.iconView to a custom UIView.
marker.iconView = customUIView()
func customUIView()-> UIView
{
var theView:UIView
theView.isUserInteractionEnabled = true
let gesture = UITapGestureRecognizer(target: self, action:
#selector (self.popAction(sender:)))
theView.addGestureRecognizer(gesture)
}
The UIView is pretty much just a textbox and when the UIView is clicked I won't a popup happening from popAction.
But I can't get the gesture functionality to work and I wonder if it's because the gesture is being registered on the google map and not on the UIView.
**** Update *****
After reading the google docs i'm pretty sure i can't add a gesture to a marker.iconView because the UIView is just a "snapshot"
Instead i'm implementing GMSMapViewDelegate.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
print("markerTapped")
return true
}
This function works but what i'd like to do is pass data from my UIView that is the marker.iconView into the above func mapView and not entirely sure how.
update
So marker.iconView = customUIView(sport: sportEvent) and each sportEvent object has title, date and description. The customUIView looks like a textbox with the info.
There is a loop through an array so that each marker on the map has specific sportEvent info.
Ideally, I'd like to add a gesture to the customUIView so that when the "marker" is clicked an alert pops up with the details of sportEvent title, date and description. But the way google renders marker.iconView means user input is lost from the customUIView so I can't set a gesture on it.
So i'm looking for a workaround where I can get a particular marker clicked and then an alert pops with that sportEvent info.
So I used GMSMapViewDelegate and then when the marker is clicked func mapView fires. That's cool but I can't get the sportEvent info associated with each particular marker.
So I tried to pass the sportEvent object into func mapView but then the function doesn't seem to execute and the marker is no longer clickable.
Thx.
The way I approached it was creating a custom GMSMarker. This will create the points on your mapView.
You want to pass in your sportEvent object when initializing the custom marker (i.e. something like CustomMarker(with: sportEvent))
The GMSMarker object has some properties you can set which you can find here but, some of the notable ones include:
title, snippet (text beneath title) which is what you want to set from your sportEvent object.
So, in your custom marker you can do:
Class CustomMarker: GMSMarker {
var title: String
var desc: String
...
init(with sportEvent: SportEvent) {
// do some validation before setting this assumes all values are set correctly
self.title = sportEvent.title //(assuming `.title` is a string)
self.desc = sportEvent.description
...
super.init()
title = self.title
snippet = self.desc
}
}
Note that the custom GMSMarker may need a position property set which is just a CLLocationCoordinate2D i.e. (position = CLLocationCoordinate2D(latitude: sportEvent.latitude, longitude: sportEvent.longitude)
This will by default show you a mini marker info window with your sportEvent object.
If you want to further customize the marker info window you can take a look at markerInfoWindow
It returns a view if it exists. What I did was create my view programatically and I passed in my custom marker into the view and set everything accordingly there.
Like so:
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
let customMarker = marker as! CustomMarker
return myCustomView(with: customMarker)
}
Where myCustomView is a method that returns a UIView`
func myCustomView(with customMarker: CustomMarker) -> UIView {
// Set view programatically here with your customMarker
}
Hope it helps!

How in Swift to display details of multiple dropped pins

In Swift, I can add map annotation and display details using segue of a dropped pin when the user clicks the "i", but I am having trouble displaying details of multiple dropped pins using segue; unlike ViewTable no index is involved here. How do I do that?
Can this give you some hint?
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
calloutAccessoryControlTapped control: UIControl!) {
//get the annotation ,maybe you need cast the type
// let anno = view.annotation
//performSegue here
}

Google Maps iOS SDK Touch Events

I'm trying to add an UIGestureRecognizer to one the whole google map view.
I want to get notified if i touch the map ( not the marker ), but i don't know how. what i did is this inside viewDidLoad:
UITapGestureRecognizer* tapRec = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(didTapMap:)];
[mapView_ addGestureRecognizer:tapRec];
and outside viewDidLoad:
- (void)didTapMap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Touched map");
}
but this method don't work and don't print anything on the console window..
please help me and show me how to do it please
I think what you need is already part of the map's delegate
/**
* Called after a tap gesture at a particular coordinate, but only if a marker
* was not tapped. This is called before deselecting any currently selected
* marker (the implicit action for tapping on the map).
*/
- (void)mapView:(GMSMapView *)mapView
didTapAtCoordinate:(CLLocationCoordinate2D)coordinate;
there are other methods in that delegate, take a look a them too.
Use the following function for Swift:
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D)
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
// In My Case Im adding one overlay view on marker tap.
// infoWindow is a subclass of UIview in my code
infoWindow.removeFromSuperview()
infoWindow = loadNiB()
infoWindow.center = mapView.projection.point(for: marker.position)
infoWindow.center.y = infoWindow.center.y - sizeForOffset(view: infoWindow)
self.view.addSubview(infoWindow)
return false
}
for Swift 3
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
NSLog(#"Touched map");
}
- (void) mapView:(GMSMapView *)mapView didTapAtCoordinate (CLLocationCoordinate2D)coordinate{
NSLog(#"User did tap at coordinate %f, %f", coordinate.latitude, coordinate.longitude) ;
NSLog(#"Map view center %f %f and zoom is %f", mapView.camera.target.latitude, mapView.camera.target.longitude, mapView.camera.zoom) ;
}
}