[ios, macos] Center shape annotation's callout when offscreen. (#10255)

* [ios, macos] Center annotation's anchor to tap point when coordinate center is offscreen.

* [ios, macos] Update changelogs.
This commit is contained in:
Fabian Guerra Soto
2017-11-01 08:20:48 -04:00
committed by GitHub
parent 03d3aee6fc
commit 63f7963a93
4 changed files with 47 additions and 28 deletions

View File

@@ -32,6 +32,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added `-[MGLMapView cameraThatFitsShape:direction:edgePadding:]` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
* Added support selection of shape and polyline annotations.([#9984](https://github.com/mapbox/mapbox-gl-native/pull/9984))
* Fixed an issue where view annotations could be slightly misaligned. View annotation placement is now rounded to the nearest pixel. ([#10219](https://github.com/mapbox/mapbox-gl-native/pull/10219))
* Fixed an issue where a shape annotation callout was not displayed if the centroid was not visible. ([#10255](https://github.com/mapbox/mapbox-gl-native/pull/10255))
### Other changes

View File

@@ -1615,7 +1615,9 @@ public:
id<MGLAnnotation>annotation = [self annotationForGestureRecognizer:singleTap persistingResults:YES];
if(annotation)
{
[self selectAnnotation:annotation animated:YES];
CGPoint calloutPoint = [singleTap locationInView:self];
CGRect positionRect = [self positioningRectForAnnotation:annotation defaultCalloutPoint:calloutPoint];
[self selectAnnotation:annotation animated:YES calloutPositioningRect:positionRect];
}
else
{
@@ -3979,6 +3981,12 @@ public:
}
- (void)selectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated
{
CGRect positioningRect = [self positioningRectForAnnotation:annotation defaultCalloutPoint:CGPointZero];
[self selectAnnotation:annotation animated:animated calloutPositioningRect:positioningRect];
}
- (void)selectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated calloutPositioningRect:(CGRect)calloutPositioningRect
{
if ( ! annotation) return;
@@ -3995,9 +4003,6 @@ public:
if (annotationTag == MGLAnnotationTagNotFound) return;
}
// By default attempt to use the GL annotation image frame as the positioning rect.
CGRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag];
MGLAnnotationView *annotationView = nil;
if (annotation != self.userLocation)
@@ -4005,21 +4010,12 @@ public:
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
annotationView = annotationContext.annotationView;
if (annotationView && annotationView.enabled) {
{
// Annotations represented by views use the view frame as the positioning rect.
positioningRect = annotationView.frame;
[annotationView.superview bringSubviewToFront:annotationView];
[annotationView setSelected:YES animated:animated];
// Annotations represented by views use the view frame as the positioning rect.
calloutPositioningRect = annotationView.frame;
[annotationView.superview bringSubviewToFront:annotationView];
[annotationView setSelected:YES animated:animated];
}
}
}
// The client can request that any annotation be selected (even ones that are offscreen).
// The annotation can’t be selected if no part of it is hittable.
if ( ! CGRectIntersectsRect(positioningRect, self.bounds) && annotation != self.userLocation)
{
return;
}
self.selectedAnnotation = annotation;
@@ -4049,7 +4045,7 @@ public:
if (_userLocationAnnotationIsSelected)
{
positioningRect = [self.userLocationAnnotationView.layer.presentationLayer frame];
calloutPositioningRect = [self.userLocationAnnotationView.layer.presentationLayer frame];
CGRect implicitAnnotationFrame = [self.userLocationAnnotationView.layer.presentationLayer frame];
CGRect explicitAnnotationFrame = self.userLocationAnnotationView.frame;
@@ -4065,7 +4061,7 @@ public:
if ([calloutView.leftAccessoryView isKindOfClass:[UIControl class]])
{
UITapGestureRecognizer *calloutAccessoryTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleCalloutAccessoryTapGesture:)];
action:@selector(handleCalloutAccessoryTapGesture:)];
[calloutView.leftAccessoryView addGestureRecognizer:calloutAccessoryTap];
}
@@ -4078,7 +4074,7 @@ public:
if ([calloutView.rightAccessoryView isKindOfClass:[UIControl class]])
{
UITapGestureRecognizer *calloutAccessoryTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleCalloutAccessoryTapGesture:)];
action:@selector(handleCalloutAccessoryTapGesture:)];
[calloutView.rightAccessoryView addGestureRecognizer:calloutAccessoryTap];
}
@@ -4088,7 +4084,7 @@ public:
calloutView.delegate = self;
// present popup
[calloutView presentCalloutFromRect:positioningRect
[calloutView presentCalloutFromRect:calloutPositioningRect
inView:self.glView
constrainedToView:self.glView
animated:animated];
@@ -4115,6 +4111,27 @@ public:
return calloutView;
}
/// Returns the rectangle that represents the annotation image of the annotation
/// with the given tag. This rectangle is fitted to the image’s alignment rect
/// and is appropriate for positioning a popover.
/// If a shape annotation is visible but its centroid is not, and a default point is specified,
/// the callout view is anchored to the default callout point.
- (CGRect)positioningRectForAnnotation:(id <MGLAnnotation>)annotation defaultCalloutPoint:(CGPoint)calloutPoint
{
MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation];
CGRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag];
// For annotations which `coordinate` falls offscreen it will use the current tap point as anchor instead.
if ( ! CGRectIntersectsRect(positioningRect, self.bounds) && annotation != self.userLocation)
{
if (!CGPointEqualToPoint(calloutPoint, CGPointZero)) {
positioningRect = CGRectMake(calloutPoint.x, calloutPoint.y, positioningRect.size.width, positioningRect.size.height);
}
}
return positioningRect;
}
/// Returns the rectangle that represents the annotation image of the annotation
/// with the given tag. This rectangle is fitted to the image’s alignment rect
/// and is appropriate for positioning a popover.

View File

@@ -28,6 +28,7 @@
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
* Added `-[MGLMapView cameraThatFitsShape:direction:edgePadding:]` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
* Added support selection of shape and polyline annotations.([#9984](https://github.com/mapbox/mapbox-gl-native/pull/9984))
* Fixed an issue where a shape annotation callout was not displayed if the centroid was not visible. ([#10255](https://github.com/mapbox/mapbox-gl-native/pull/10255))
### Other changes

View File

@@ -1488,7 +1488,7 @@ public:
if (hitAnnotationTag != _selectedAnnotationTag) {
id <MGLAnnotation> annotation = [self annotationWithTag:hitAnnotationTag];
NSAssert(annotation, @"Cannot select nonexistent annotation with tag %u", hitAnnotationTag);
[self selectAnnotation:annotation];
[self selectAnnotation:annotation atPoint:gesturePoint];
}
} else {
[self deselectAnnotation:self.selectedAnnotation];
@@ -2216,11 +2216,11 @@ public:
- (void)selectAnnotation:(id <MGLAnnotation>)annotation
{
// Only point annotations can be selected.
if (!annotation || [annotation isKindOfClass:[MGLMultiPoint class]]) {
return;
}
[self selectAnnotation:annotation atPoint:NSZeroPoint];
}
- (void)selectAnnotation:(id <MGLAnnotation>)annotation atPoint:(NSPoint)gesturePoint
{
id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
if (annotation == selectedAnnotation) {
return;
@@ -2235,10 +2235,10 @@ public:
[self addAnnotation:annotation];
}
// The annotation can’t be selected if no part of it is hittable.
// The annotation's anchor will bounce to the current click.
NSRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag];
if (NSIsEmptyRect(NSIntersectionRect(positioningRect, self.bounds))) {
return;
positioningRect = CGRectMake(gesturePoint.x, gesturePoint.y, positioningRect.size.width, positioningRect.size.height);
}
self.selectedAnnotation = annotation;