[ios] Observe annotation coordinates

MGLMapView observes changes to the coordinate property of each MGLAnnotation added to it. Changing the coordinate property in a KVO-compliant way causes the annotation to be relocated and its callout view, if present, to be dismissed. To avoid observing the same annotation twice yet also avoid expensive lookups when adding or removing annotations, MGLMapView indexes added point annotations in an NSMutableSet.

In iosapp, tapping a callout view moves the selected annotation to the center of the screen and deselects it.

Fixes #1980.
This commit is contained in:
Minh Nguyễn
2016-04-17 16:43:05 -07:00
committed by Minh Nguyễn
parent 7a5406bc50
commit 8a4c2d4b0e
3 changed files with 41 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ Mapbox welcomes participation and contributions from everyone. If you’d like
- Removed the `armv7s` slice from the SDK to reduce its size. iPhone 5 and iPhone 5c automatically use the `armv7` slice instead. ([#4641](https://github.com/mapbox/mapbox-gl-native/pull/4641))
- The user dot now moves smoothly between user location updates while user location tracking is disabled. ([#1582](https://github.com/mapbox/mapbox-gl-native/pull/1582))
- User location heading updates now resume properly when an app becomes active again. ([#4674](https://github.com/mapbox/mapbox-gl-native/pull/4674))
- An MGLAnnotation can be relocated by changing its `coordinate` property in a KVO-compliant way. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835))
- Setting the `image` property of an MGLAnnotationImage to `nil` resets it to the default red pin image and reclaims resources that can be used to customize additional annotations. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835))
- Fixed an issue preventing KVO change notifications from being generated on MGLMapView’s `userTrackingMode` key path when `-setUserTrackingMode:animated:` is called. ([#4724](https://github.com/mapbox/mapbox-gl-native/pull/4724))
- Fixed a hang that could occur if the host application attempts to set user defaults on a background queue. ([#4745](https://github.com/mapbox/mapbox-gl-native/pull/4745))

View File

@@ -719,4 +719,15 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
return nil;
}
- (void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id <MGLAnnotation>)annotation
{
if ( ! [annotation isKindOfClass:[MGLPointAnnotation class]])
{
return;
}
MGLPointAnnotation *point = annotation;
point.coordinate = [self.mapView convertPoint:self.mapView.center toCoordinateFromView:self.mapView];
}
@end

View File

@@ -191,6 +191,7 @@ public:
NS_MUTABLE_ARRAY_OF(NSURL *) *_bundledStyleURLs;
MGLAnnotationContextMap _annotationContextsByAnnotationTag;
NS_MUTABLE_SET_OF(id <MGLAnnotation>) *_pointAnnotations;
/// Tag of the selected annotation. If the user location annotation is selected, this ivar is set to `MGLAnnotationTagNotFound`.
MGLAnnotationTag _selectedAnnotationTag;
BOOL _userLocationAnnotationIsSelected;
@@ -343,6 +344,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
// Set up annotation management and selection state.
_annotationImagesByIdentifier = [NSMutableDictionary dictionary];
_annotationContextsByAnnotationTag = {};
_pointAnnotations = [NSMutableSet set];
_selectedAnnotationTag = MGLAnnotationTagNotFound;
_annotationsNearbyLastTap = {};
@@ -1608,6 +1610,21 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
[MGLMapboxEvents ensureMetricsOptoutExists];
}
}
else if ([keyPath isEqualToString:@"coordinate"] && [object conformsToProtocol:@protocol(MGLAnnotation)])
{
id <MGLAnnotation> annotation = object;
MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation];
if (annotationTag != MGLAnnotationTagNotFound)
{
const mbgl::LatLng latLng = MGLLatLngFromLocationCoordinate2D(annotation.coordinate);
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
_mbglMap->updatePointAnnotation(annotationTag, { latLng, annotationImage.styleIconIdentifier.UTF8String ?: "" });
if (annotationTag == _selectedAnnotationTag)
{
[self deselectAnnotation:annotation animated:YES];
}
}
}
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
@@ -2417,6 +2434,12 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
[annotationImages addObject:annotationImage];
points.emplace_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate), symbolName.UTF8String ?: "");
if ( ! [_pointAnnotations containsObject:annotation] && [annotation isKindOfClass:[NSObject class]])
{
[(NSObject *)annotation addObserver:self forKeyPath:@"coordinate" options:0 context:NULL];
[_pointAnnotations addObject:annotation];
}
}
}
@@ -2571,6 +2594,12 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
}
_annotationContextsByAnnotationTag.erase(annotationTag);
if ([annotation isKindOfClass:[NSObject class]])
{
[(NSObject *)annotation removeObserver:self forKeyPath:@"coordinate"];
}
[_pointAnnotations removeObject:annotation];
}
if ( ! annotationTagsToRemove.empty())