Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[ios] fixes #2490: add annotation image enabled property #2501

Merged
merged 1 commit into from
Oct 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/mbgl/ios/MGLAnnotationImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ NS_ASSUME_NONNULL_BEGIN
* If you define distinctly different types of annotations (with distinctly different annotation images to go with them), you can differentiate between the annotation types by specifying different reuse identifiers for each one. */
@property (nonatomic, readonly) NSString *reuseIdentifier;

/** A Boolean value indicating whether the annotation is enabled.
*
* The default value of this property is `YES`. If the value of this property is `NO`, the annotation image ignores touch events and cannot be selected. */
@property (nonatomic, getter=isEnabled) BOOL enabled;

@end

NS_ASSUME_NONNULL_END
14 changes: 13 additions & 1 deletion ios/app/MBXViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ - (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotati
NSString *title = [(MGLPointAnnotation *)annotation title];
NSString *lastTwoCharacters = [title substringFromIndex:title.length - 2];

UIColor *color;

// make every tenth annotation blue
if ([lastTwoCharacters hasSuffix:@"0"]) {
color = [UIColor blueColor];
} else {
color = [UIColor redColor];
}

MGLAnnotationImage *image = [mapView dequeueReusableAnnotationImageWithIdentifier:lastTwoCharacters];

if ( ! image)
Expand All @@ -367,7 +376,7 @@ - (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotati

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGContextSetFillColorWithColor(ctx, [[[UIColor redColor] colorWithAlphaComponent:0.75] CGColor]);
CGContextSetFillColorWithColor(ctx, [[color colorWithAlphaComponent:0.75] CGColor]);
CGContextFillRect(ctx, rect);

CGContextSetStrokeColorWithColor(ctx, [[UIColor blackColor] CGColor]);
Expand All @@ -385,6 +394,9 @@ - (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotati

image = [MGLAnnotationImage annotationImageWithImage:UIGraphicsGetImageFromCurrentImageContext() reuseIdentifier:lastTwoCharacters];

// don't allow touches on blue annotations
if ([color isEqual:[UIColor blueColor]]) image.enabled = NO;

UIGraphicsEndImageContext();
}

Expand Down
1 change: 1 addition & 0 deletions platform/ios/MGLAnnotationImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ - (instancetype)initWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuse
{
_image = image;
_reuseIdentifier = [reuseIdentifier copy];
_enabled = YES;
}

return self;
Expand Down
91 changes: 64 additions & 27 deletions platform/ios/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/std.hpp>

#import "Mapbox.h"

Expand All @@ -37,6 +38,7 @@

#import <algorithm>
#import <cstdlib>
#import <unordered_set>

class MBGLView;

Expand All @@ -52,6 +54,7 @@
const CGFloat MGLMinimumPitch = 0;
const CGFloat MGLMaximumPitch = 60;
const CLLocationDegrees MGLAngularFieldOfView = M_PI / 6.;
const std::string spritePrefix = "com.mapbox.sprites.";

NSString *const MGLAnnotationIDKey = @"MGLAnnotationIDKey";
NSString *const MGLAnnotationSymbolKey = @"MGLAnnotationSymbolKey";
Expand Down Expand Up @@ -1158,44 +1161,78 @@ - (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap

if (nearbyAnnotations.size())
{
// there is at least one nearby annotation; select one
//
// first, sort for comparison and iteration
std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end());
// pare down nearby annotations to only enabled ones
NSEnumerator *metadataEnumerator = [self.annotationMetadataByAnnotation objectEnumerator];
NSString *prefix = [NSString stringWithUTF8String:spritePrefix.c_str()];
std::unordered_set<uint32_t> disabledAnnotationIDs;

if (nearbyAnnotations == self.annotationsNearbyLastTap)
while (NSDictionary *metadata = [metadataEnumerator nextObject])
{
// the selection candidates haven't changed; cycle through them
if (self.selectedAnnotation &&
[[[self.annotationMetadataByAnnotation objectForKey:self.selectedAnnotation]
objectForKey:MGLAnnotationIDKey] unsignedIntValue] == self.annotationsNearbyLastTap.back())
// This iterates ALL annotations' metadata dictionaries, using their
// reuse identifiers to get at the stored annotation image objects,
// which we can then query for enabled status.
NSString *reuseIdentifier = [metadata[MGLAnnotationSymbolKey] stringByReplacingOccurrencesOfString:prefix
withString:@""
options:NSAnchoredSearch
range:NSMakeRange(0, prefix.length)];

MGLAnnotationImage *annotationImage = self.annotationImages[reuseIdentifier];

if (annotationImage.isEnabled == NO)
{
// the selected annotation is the last in the set; cycle back to the first
// note: this could be the selected annotation if only one in set
newSelectedAnnotationID = self.annotationsNearbyLastTap.front();
disabledAnnotationIDs.emplace([metadata[MGLAnnotationIDKey] unsignedIntValue]);
}
else if (self.selectedAnnotation)
}

if (disabledAnnotationIDs.size())
{
// Clear out any nearby annotations that are in our set of
// disabled annotations.
mbgl::util::erase_if(nearbyAnnotations, [&](const uint32_t annotationID) {
return disabledAnnotationIDs.count(annotationID) != 0;
});
}

// only proceed if there are still annotations
if (nearbyAnnotations.size() > 0)
{
// first, sort for comparison and iteration
std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end());

if (nearbyAnnotations == self.annotationsNearbyLastTap)
{
// otherwise increment the selection through the candidates
uint32_t currentID = [[[self.annotationMetadataByAnnotation objectForKey:self.selectedAnnotation] objectForKey:MGLAnnotationIDKey] unsignedIntValue];
auto result = std::find(self.annotationsNearbyLastTap.begin(), self.annotationsNearbyLastTap.end(), currentID);
auto distance = std::distance(self.annotationsNearbyLastTap.begin(), result);
newSelectedAnnotationID = self.annotationsNearbyLastTap[distance + 1];
// the selection candidates haven't changed; cycle through them
if (self.selectedAnnotation &&
[[[self.annotationMetadataByAnnotation objectForKey:self.selectedAnnotation]
objectForKey:MGLAnnotationIDKey] unsignedIntValue] == self.annotationsNearbyLastTap.back())
{
// the selected annotation is the last in the set; cycle back to the first
// note: this could be the selected annotation if only one in set
newSelectedAnnotationID = self.annotationsNearbyLastTap.front();
}
else if (self.selectedAnnotation)
{
// otherwise increment the selection through the candidates
uint32_t currentID = [[[self.annotationMetadataByAnnotation objectForKey:self.selectedAnnotation] objectForKey:MGLAnnotationIDKey] unsignedIntValue];
auto result = std::find(self.annotationsNearbyLastTap.begin(), self.annotationsNearbyLastTap.end(), currentID);
auto distance = std::distance(self.annotationsNearbyLastTap.begin(), result);
newSelectedAnnotationID = self.annotationsNearbyLastTap[distance + 1];
}
else
{
// no current selection; select the first one
newSelectedAnnotationID = self.annotationsNearbyLastTap.front();
}
}
else
{
// no current selection; select the first one
// start tracking a new set of nearby annotations
self.annotationsNearbyLastTap = nearbyAnnotations;

// select the first one
newSelectedAnnotationID = self.annotationsNearbyLastTap.front();
}
}
else
{
// start tracking a new set of nearby annotations
self.annotationsNearbyLastTap = nearbyAnnotations;

// select the first one
newSelectedAnnotationID = self.annotationsNearbyLastTap.front();
}
}
else
{
Expand Down