diff --git a/ios/app/MBXCustomCalloutView.h b/ios/app/MBXCustomCalloutView.h new file mode 100644 index 000000000..43dfac414 --- /dev/null +++ b/ios/app/MBXCustomCalloutView.h @@ -0,0 +1,16 @@ +#import +#import + +/* + * Basic custom callout view to demonstrate how to + * add your own on your app. Will only show the + * callout title for demonstration purpose. + */ + +@interface MBXCustomCalloutView : UIView + +@property (nonatomic, copy) NSString *title, *subtitle; +@property (nonatomic, strong) UIView *leftAccessoryView, *rightAccessoryView; +@property (nonatomic, weak) id delegate; + +@end diff --git a/ios/app/MBXCustomCalloutView.m b/ios/app/MBXCustomCalloutView.m new file mode 100644 index 000000000..fa83dc602 --- /dev/null +++ b/ios/app/MBXCustomCalloutView.m @@ -0,0 +1,82 @@ +#import "MBXCustomCalloutView.h" + +static CGFloat const tipHeight = 10.0; +static CGFloat const tipWidth = 10.0; + +@interface MBXCustomCalloutView () + +@property (strong, nonatomic) UILabel *mainLabel; + +@end + +@implementation MBXCustomCalloutView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + self.backgroundColor = [UIColor clearColor]; + _mainLabel = [[UILabel alloc] initWithFrame: CGRectZero]; + _mainLabel.backgroundColor = [UIColor clearColor]; + + [self addSubview: _mainLabel]; + } + return self; +} + + +#pragma mark - API + +- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated +{ + [view addSubview:self]; + // prepare title label + self.mainLabel.text = self.title; + [self.mainLabel sizeToFit]; + // prepare our frame + CGFloat frameWidth = self.mainLabel.bounds.size.width; + CGFloat frameHeight = self.mainLabel.bounds.size.height * 2.0; + CGFloat frameOriginX = rect.origin.x + (rect.size.width/2.0) - (frameWidth/2.0); + CGFloat frameOriginY = rect.origin.y - frameHeight; + self.frame = CGRectMake(frameOriginX, frameOriginY, + frameWidth, frameHeight); +} + +- (void)dismissCalloutAnimated:(BOOL)animated +{ + if (self.superview) + [self removeFromSuperview]; +} + +#pragma mark - internals + +- (void)drawRect:(CGRect)rect +{ + UIColor *fillColor = [UIColor colorWithWhite:0.7 alpha:1.0]; + + CGFloat tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0); + CGPoint tipBottom = CGPointMake(rect.origin.x + (rect.size.width / 2.0), rect.origin.y +rect.size.height); + CGFloat heightWithoutTip = rect.size.height - tipHeight; + + // draw the white background with tip + CGContextRef ctxt = UIGraphicsGetCurrentContext(); + + CGMutablePathRef tipPath = CGPathCreateMutable(); + CGPathMoveToPoint(tipPath, NULL, 0, 0); + CGPathAddLineToPoint(tipPath, NULL, 0, heightWithoutTip); + CGPathAddLineToPoint(tipPath, NULL, tipLeft, heightWithoutTip); + CGPathAddLineToPoint(tipPath, NULL, tipBottom.x, tipBottom.y); + CGPathAddLineToPoint(tipPath, NULL, tipLeft + tipWidth, heightWithoutTip); + CGPathAddLineToPoint(tipPath, NULL, CGRectGetWidth(rect), heightWithoutTip); + CGPathAddLineToPoint(tipPath, NULL, CGRectGetWidth(rect), 0); + CGPathCloseSubpath(tipPath); + + [fillColor setFill]; + CGContextAddPath(ctxt, tipPath); + CGContextFillPath(ctxt); + CGPathRelease(tipPath); +} + + +@end diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 21a6a2aea..e67003b39 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -1,4 +1,5 @@ #import "MBXViewController.h" +#import "MBXCustomCalloutView.h" #import #import @@ -7,6 +8,7 @@ #import static UIColor *const kTintColor = [UIColor colorWithRed:0.120 green:0.550 blue:0.670 alpha:1.000]; +static NSString * const kCustomCalloutTitle = @"Custom Callout"; static const CLLocationCoordinate2D WorldTourDestinations[] = { { 38.9131982, -77.0325453144239 }, @@ -151,6 +153,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { @"Add 10,000 Points", @"Add Test Shapes", @"Start World Tour", + @"Add 1 custom Point", @"Remove Annotations", @"Toggle Custom Style Layer", nil]; @@ -261,9 +264,13 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 9) { - [self.mapView removeAnnotations:self.mapView.annotations]; + [self presentAnnotationWithCustomCallout]; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 10) + { + [self.mapView removeAnnotations:self.mapView.annotations]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 11) { if (_isShowingCustomStyleLayer) { @@ -377,6 +384,18 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { [self.mapView removeCustomStyleLayerWithIdentifier:@"mbx-custom"]; } +- (void)presentAnnotationWithCustomCallout +{ + [self.mapView removeAnnotations:self.mapView.annotations]; + + MGLPointAnnotation *annotation = [MGLPointAnnotation new]; + annotation.coordinate = CLLocationCoordinate2DMake(48.8533940, 2.3775439); + annotation.title = kCustomCalloutTitle; + + [self.mapView addAnnotation:annotation]; + [self.mapView showAnnotations:@[annotation] animated:YES]; +} + - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress { if (longPress.state == UIGestureRecognizerStateBegan) @@ -475,7 +494,11 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { - (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotation:(id __nonnull)annotation { - if ([annotation.title isEqualToString:@"Dropped Marker"]) return nil; // use default marker + if ([annotation.title isEqualToString:@"Dropped Marker"] + || [annotation.title isEqualToString:kCustomCalloutTitle]) + { + return nil; // use default marker + } NSString *title = [(MGLPointAnnotation *)annotation title]; if (!title.length) return nil; @@ -576,4 +599,16 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { }]; } +- (UIView *)mapView:(__unused MGLMapView *)mapView customCalloutViewForAnnotation:(id)annotation +{ + if ([annotation respondsToSelector:@selector(title)] + && [annotation.title isEqualToString:kCustomCalloutTitle]) + { + MBXCustomCalloutView *calloutView = [[MBXCustomCalloutView alloc] init]; + calloutView.title = annotation.title; + return calloutView; + } + return nil; +} + @end diff --git a/ios/app/mapboxgl-app.gypi b/ios/app/mapboxgl-app.gypi index def04cdc3..4fa0ba664 100644 --- a/ios/app/mapboxgl-app.gypi +++ b/ios/app/mapboxgl-app.gypi @@ -28,6 +28,8 @@ './main.m', './MBXAppDelegate.h', './MBXAppDelegate.m', + './MBXCustomCalloutView.h', + './MBXCustomCalloutView.m', './MBXViewController.h', './MBXViewController.mm', ],