I am trying to show thousands of potential pins (Annotations) to the user on the MKMapView. Does anyone know if the map is using occlusion culling to render only the visible annotations?
This is for iOS 7+ using xCode 6.4
When talking about managing large number of annotations, we should differentiate between "annotations" and "annotation views". When you add many annotations to a map view, the collection of those light-weight MKAnnotation objects remain in the annotations array. But the map view offers a mechanism to mitigate the memory issues that can arise from a large number of associated "annotation views".
When you add thousands of annotations to a map view, the only annotation views that are instantiated are those that are visible (and those that near the visible portion of the map. If you properly use dequeueReusableAnnotationViewWithIdentifier in viewForAnnotation, as you scroll and annotations views fall out of view, when it needs new annotation views, it will recycle those that have scrolled out of view:
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
} else {
annotationView?.annotation = annotation
}
return annotationView
}
Thus, this keeps the number of annotation views to some manageable number, not necessarily instantiating new annotation views until they're absolutely needed (i.e. there don't happen to be any old annotation views that have scrolled out of view, available for reuse).
If, however, the user zooms out on the map so there are an unmanageable number of annotation views visible simultaneously, you have to manage this situation yourself. Back in WWDC 2011, there was a video Visualizing Information Geographically with MapKit that demonstrates interesting model when dealing with tons of annotations. Specifically, they deal with the problem that you zoom out and there are so many annotation views that they start overlapping and become too numerous. This video demonstrates an approach in which you aggregate annotation views together as you scroll out (if necessary). The implementation is fairly rudimentary, but it illustrates the concept.
Related
I'm having some difficulties with Mapbox iOS.
I'm adding annotations on my map, but when they are very close (actually overlap) to the user annotation (i.e MGLUserLocation) taps do not pass to the other annotations.
I have tried to play with the z-order both for the user annotation (setting it to. 0/-1 or any lower value) while increasing the value of the other annotations but with no success
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation)
Is always called with the user annotation.
I'm using a custom view for the user annotation and I tried to set its isEnable property false as well. Moreover, when I try to override the override open func tionsetSelected(_ selected: Bool, animated: Bool) In the custom view it is not called (no matter if it's isEnabled is true/false...)
It seems like the "halo" around the user location annotation make any tap to interact with the user annotation only - even if there are other objects that seems to be before it...
I was thinking as a last option to setup aUIGestureRecognizer on the relevant view that the user annotations "hides"... But am I missing something about the special user annotation in Mapbox?
I create a simple project trying to mimic as best as possible the problem in my original project which is not public - Repo
Here is an example of the capability I'm trying to achieve in Google Maps
Found the solution which I think it is utilising Mapbox API in the best way:
MGLUserLocationAnnotationView has a property called hitTestLayer: CALayer?
You can just override it and supply with the size of the clickable layer you wish to enable.... In my case I don't care for user annotation interaction so I set it to zero (I updated the code in the example repo as well)
I have a mapView in which I want to show user's current location. However, I don't want to centre the mapView to that location (it is centred to other location). So, for that reason, I don't get coordinates for the user's location to set the region. I just call showsUserLocation and set it to true. Everything works fine, except the fact that this makes my mapView show user's current location just as a pin. I would like it to be in a form of a default blue dot.
Related to the problem above, I have two questions:
1) Why does it show user's current location as a pin?
2) How can I make it show user's current location as a blue dot?
If you know the answers to these questions (or only to one of them) I would appreciate your help.
Everything depends on your implementation of the map view delegate's mapView(_:viewFor:). You are probably returning a pin annotation.
You can distinguish the annotation provided by the map view as the user's location by checking its class, which will be MKUserLocation. If you want the default blue dot, return nil for that class.
In Swift 5
We need to check the type of annotation, if it is a user location do not want to return a pin:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
[... code for the other annotations ... ]
}
Now you will see your location as a classic blue dot.
I have a traditional map from mapKit with a set of pins at their respective location. I am trying to keep the pins at the same place, while making the map invisible.
Is there any way to do this?
Thank you,
OK, I have to admit this one made me really curious! I don't know of a clean way of doing what you want, although I suspect there might be interesting hacks you can do around adding overlays.
One solution you might want to experiment with is to use viewForAnnotation() to pull out the location of each pin annotation on the map, transform that to your view, then add custom views in its place. You can then hide the entire map (which would hide its pins), leaving your fake pins in place.
Off the top of my head, it would look something like this:
let annotations = mapView.annotations
for annotation in annotations {
if let annotationView = mapView.viewForAnnotation(annotation) {
let transformedFrame = view.convertRect(annotationView.frame, fromView: annotationView.superview)
let testView = UIView(frame: transformedFrame)
testView.backgroundColor = UIColor.redColor()
view.addSubview(testView)
}
}
You will have problems when the map view moves, though, so you might need to keep track of your fake pins and move them appropriately.
I'm drawing a MKMapView in my iOS app, and on this map are some annotations, with custom images representing them. The image changes slightly (has a glow) when a specific annotation is selected.
To do this, I'm using the mapView(mapView: MKMapView!, didSelectAnnotationView view: MKAnnotationView!) delegate method to change the image (by changing view.annotation.image). This seems to work fine.
However, when I use the mapView(mapView: MKMapView!, didDeselectAnnotationView view: MKAnnotationView!) method to change the image back after it's deselected, it redraws the annotation in the upper left corner of the map. Any user interaction with the map then redraws it in its proper place immediately, so it's like the map isn't being refreshed after the method call until a click or something is made.
Is this actually the correct way to change an annotation's image (by overwriting the current view.annotation.image, and if so is there a way to refresh the map?
EDIT: I've also just noticed every time I select a new annotation it drags the map center down by about 100 pixels. Is there something I'm missing that I need to do after calling either of these two methods mentioned above?
You could try removing and re-adding the annotation using mapView.removeAnnotation(yourAnnotation) and mapview.addAnnotation(yourAnnotation) with the new image
So `MKAnnotation's. Fun stuff.
My questions:
What's the difference between an annotation's title and its subtitle and how does that affect the visual component of the annotation?
What's the difference between a MKPinAnnotationView and a MKAnnotationView?
Are there different types of map annotations in iOS apart from pins?
Title is main heading of your pin.
The subtitle is actually displaying the address/(common info) of the dropped pin.You can store other deeply information of related to title that is puted on pin.
MKAnnotation is a protocol you need to adopt if you wish to show your object on a MKMapView. The coordinate property tells MKMapView where to place it. title and subtitle properties are optional but if you wish to show a callout view you are expected to implement title at a minimum.
MKAnnotationView visually presents the MKAnnotation on the MKMapView. The image property can be set to determine what to show for the annotation. However you can subclass it and implement drawRect: yourself.
MKPinAnnotationView is a subclass of MKAnnotationView that uses a Pin graphic as the image property. You can set the pin color and drop animation.
Don't forget about the leftCalloutAccessoryView and the rightCalloutAccessoryView properties of MKAnnotationView that can be used to customize the callout view.
The title and subtitle are displayed when a pin is selected on the map. The subtitle simply falls below the title.
MKPinAnnotationView is simply an specialized form of MKAnnotationView that knows how to draw a pin (and a shadow) and also allows setting the pin color. It's the only built-in annotation view with an image, you have to make your own if you want something different (but it's very easy to do).