-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Conversation
d1b32bc
to
a4b3ff5
Compare
#import "MBXAnnotationView.h" | ||
|
||
static const CGFloat size = 35.0; | ||
static const CGFloat padding = 7.5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Globals should be named the same way as classes, in UpperCamelCase with a prefix.
annotationImage.styleIconIdentifier = @(points[i].icon.c_str()); | ||
id <MGLAnnotation> annotation = annotations[i]; | ||
id<MGLAnnotation> annotation = annotations[i]; | ||
NSValue *annotationValue = [NSValue valueWithNonretainedObject:annotation]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing code is already more indirect than it should be: we should build the MGLAnnotationContext
s upfront, in the loop up above, and store them in a vector
. We can assume that Map::addPointAnnotations()
adds the annotations in order, so this loop would only need to associate the new tags with their annotation contexts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I will refactor in a future commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -750,6 +753,20 @@ - (void)glkView:(__unused GLKView *)view drawInRect:(__unused CGRect)rect | |||
_mbglMap->render(); | |||
|
|||
[self updateUserLocationAnnotationView]; | |||
|
|||
// Hide all annotation views |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code runs 60 times a second due to the CADisplayLink. Intuitively, I’d expect hiding, repositioning, and showing views in this relatively hot code to be a bit of a drag on performance. Can we move this into a separate method that gets called when appropriate, for example in -notifyMapChange:
, as well as in -observeValueForKeyPath:ofObject:change:context:
when an annotation’s coordinate
key path changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely. I'll work on that next.
@boundsj I have been running at the Android equivalent and looking into how we can efficiently manage which annotations are currently visible by using I noticed the following scenario: for the following screen I received the When I slowly pan to the bottom, I'm not receiving the required map change event and I'm not able to determine that we have 4 point annotations in bounds instead of 1. For the reference my logs. @boundsj are you seeing the same behaviour on iOS? PS. note that when a region change is detected, I'm receiving multiple ones after each other. We might want to look into creating an idling system that will only act on one of these events and will ignore other ones for a certain timeout time. For Android this would make sense because it would limit the amount JNI trips. cc @1ec5 |
|
||
@property (nonatomic, weak) id<MGLAnnotationViewDelegate> delegate; | ||
|
||
// Identifier used to specifiy a reuse queue for the annotation view type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: ///
for single-line documentation comments.
I’m not sure whether the multiple events in succession reflects a problem in mbgl or in the Android SDK itself, but I haven’t personally witnessed this issue for gestures or programmatic animations. The iOS SDK uses a different pattern in which there’s only one listener for map change notifications – the We should pay special attention to where we update the annotation layer. Currently, in this PR, all annotations are being updated in |
if (annotationContext.viewReuseIdentifier) | ||
{ | ||
NSMutableArray *annotationViewReuseQueue = [self annotationViewReuseQueueForIdentifier:annotationContext.viewReuseIdentifier]; | ||
if (![annotationViewReuseQueue containsObject:annotationView]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the semantics of the reuse queue require this search to form a pointer comparison or object comparison on each view in the reuse queue? If the latter, MGLAnnotationView should have custom implementations of -isEqual:
and -hash
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a pointer comparison. This guard just protects against adding a reference to any exact same view object that was previously added to the queue. I used an array for the queue since that API feels better (as a queue) in most places -- except here where a set might make things clearer. In any case, the intention is to capture any view object that goes offscreen in the appropriate queue so that it can be reused
dbd83a4
to
b1251cc
Compare
Add an UIView subclass that can be used as the base class for all client provided UIViews for annotations. Teach MGLMapView to be able to display annotation views over the map if provided by the client delegate. For now, if the delegate provides a UIView then it will be used. If not, the map view will fall back to the old strategy of using GL annotations with an image provided by the delegate or a default image if not. The map keeps a reuse queue and will store annotation views that are panned offscreen in the queue if the application developer supplied a reuse queue identifer. The views in the queue are reused when more annotation views are required. This view reuse provides a performance gain when many annotations are shown and most of them are offscreen. iosapp now implements the new delegate method to supply a native view. Add a playground to the workspace to facilitate experimentation with new features. A playground is capable of importing frameworks if it exists in the same workspace that builds the imported framework. The initial playground demonstrates annotation views. This also fixes a crash due to nullptr in annotations array If the `annotations` method is called while the user dot's callout view was showing, the userdot annotation is represented as null in the annotation context map. This caused a crash when the null pointer was attempted to be converted into an NSArray via C array. This protects against this bug by filtering out such a null annotation.
This change eliminates the call to the problematic `annotationTagsInRect:` by using the annotation views themselves and the map view to check if a view is visible or not.
b1251cc
to
1ee1491
Compare
Updated the changelog in 54381d2. |
I added an additional issue to the tail work pile: #5059 |
Implement platform annotation view (UIViews) for iOS.
API Proposal
For native annotation views in the Mapbox SDK, I don't see any reason to stray too far from what a developer coming from the Apple's MapKit might expect. Combined with the existing Mapbox API for adding annotations this would look like:
Below is an example of how the new methods noted above might be used in a future implementation. Note that MGLMapView will expect its delegate to supply a UIView that is a subclass of a new
MGLAnnotationView
.MGLAnnotationView
will hold additional meta information about the annotation, will allow for reuse of code to deal with touch interactions, and will help when view reuse is eventuallyadded.
Next steps:
cc @1ec5 @friedbunny @tobrun