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

Make custom callout views easier to use [WIP] #4948

Closed
wants to merge 9 commits into from
4 changes: 0 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
path = .mason
url = https://github.com/mapbox/mason.git

[submodule "platform/ios/vendor/SMCalloutView"]
path = platform/ios/vendor/SMCalloutView
url = https://github.com/nfarina/calloutview.git

[submodule "platform/ios/uitest/KIF"]
path = platform/ios/uitest/KIF
url = https://github.com/kif-framework/KIF.git
13 changes: 13 additions & 0 deletions platform/darwin/src/MGLAnnotation.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
#import <CoreLocation/CoreLocation.h>
#import <TargetConditionals.h>

#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#import "MGLCalloutView.h"
#endif

#import "MGLTypes.h"

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -49,6 +54,14 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly, copy, nullable) NSString *subtitle;

#if TARGET_OS_IPHONE

@property (nonatomic) BOOL canShowCallout;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Come to think of it, these view-related properties don’t belong in a model protocol if we’re going to respect a conventional MVC pattern. MapKit places this and other callout-related properties on MKAnnotationView, which prevents the developer from customizing the callout view for custom model objects that are used as point annotations. Once #4801 lands, it may be worth moving these properties over to MGLAnnotationView.

Copy link
Contributor Author

@friedbunny friedbunny May 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where these properties live will need to be reevaluated after #4801, aye. Though, if callouts only existed on MGLAnnotationView, wouldn’t GL (e.g., MGLPointAnnotation MGLAnnotationImage) annotations not have (custom) callouts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Maybe we should put them in a separate protocol, MGLCalloutSource, that both MGLPointAnnotation and MGLAnnotationImage could conform to.


@property (nonatomic, nullable) UIView <MGLCalloutView> *calloutView;

#endif

#if !TARGET_OS_IPHONE

/** The string containing the annotation’s tooltip. */
Expand Down
13 changes: 13 additions & 0 deletions platform/darwin/src/MGLPointAnnotation.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#import "MGLCalloutView.h"
#endif

#import "MGLShape.h"

#import "MGLTypes.h"
Expand All @@ -20,6 +25,14 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;

#if TARGET_OS_IPHONE

@property (nonatomic) BOOL canShowCallout;

@property (nonatomic, nullable) UIView <MGLCalloutView> *calloutView;

#endif

@end

NS_ASSUME_NONNULL_END
13 changes: 11 additions & 2 deletions platform/darwin/src/MGLPointAnnotation.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ @implementation MGLPointAnnotation

@synthesize coordinate;

#if TARGET_OS_IPHONE
@synthesize canShowCallout;
@synthesize calloutView;
#endif

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; title = %@; subtitle = %@; coordinate = %f, %f>",
return [NSString stringWithFormat:@"<%@: %p; title = %@; subtitle = %@; coordinate = %f, %f; callout: %@ (%@)>",
NSStringFromClass([self class]), (void *)self,
self.title ? [NSString stringWithFormat:@"\"%@\"", self.title] : self.title,
self.subtitle ? [NSString stringWithFormat:@"\"%@\"", self.subtitle] : self.subtitle,
coordinate.latitude, coordinate.longitude];
coordinate.latitude, coordinate.longitude
#if TARGET_OS_IPHONE
, canShowCallout ? @"yes" : @"no", calloutView
#endif
];
}

@end
27 changes: 6 additions & 21 deletions platform/ios/app/MBXCustomCalloutView.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ @interface MBXCustomCalloutView ()
@end

@implementation MBXCustomCalloutView {
id <MGLAnnotation> _representedObject;
UIView *_leftAccessoryView;
UIView *_rightAccessoryView;
__weak id <MGLCalloutViewDelegate> _delegate;
NSString *_title;
}

@synthesize representedObject = _representedObject;
@synthesize leftAccessoryView = _leftAccessoryView;
@synthesize rightAccessoryView = _rightAccessoryView;
@synthesize delegate = _delegate;
@synthesize title = _title;

- (instancetype)initWithFrame:(CGRect)frame
{
Expand All @@ -40,16 +34,11 @@ - (instancetype)initWithFrame:(CGRect)frame

- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated
{
if ([self.delegate respondsToSelector:@selector(calloutViewWillAppear:)])
{
[self.delegate performSelector:@selector(calloutViewWillAppear:) withObject:self];
}

[view addSubview:self];
// prepare title label
if ([self.representedObject respondsToSelector:@selector(title)])
if (_title)
{
self.mainLabel.text = self.representedObject.title;
self.mainLabel.text = _title;
[self.mainLabel sizeToFit];
}
// prepare our frame
Expand All @@ -59,17 +48,14 @@ - (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToV
CGFloat frameOriginY = rect.origin.y - frameHeight;
self.frame = CGRectMake(frameOriginX, frameOriginY,
frameWidth, frameHeight);

if ([self.delegate respondsToSelector:@selector(calloutViewDidAppear:)])
{
[self.delegate performSelector:@selector(calloutViewDidAppear:) withObject:self];
}
}

- (void)dismissCalloutAnimated:(BOOL)animated
{
if (self.superview)
{
[self removeFromSuperview];
}
}

#pragma mark - internals
Expand Down Expand Up @@ -101,5 +87,4 @@ - (void)drawRect:(CGRect)rect
CGPathRelease(tipPath);
}


@end
77 changes: 43 additions & 34 deletions platform/ios/app/MBXViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ - (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useV

annotation.coordinate = coordinate;
annotation.title = title;
annotation.canShowCallout = YES;

[annotations addObject:annotation];

Expand Down Expand Up @@ -429,9 +430,11 @@ - (void)presentAnnotationWithCustomCallout
[self.mapView removeAnnotations:self.mapView.annotations];

MBXCustomCalloutAnnotation *annotation = [[MBXCustomCalloutAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(48.8533940, 2.3775439);
annotation.coordinate = CLLocationCoordinate2DMake(38.904722, -77.016389);//CLLocationCoordinate2DMake(48.8533940, 2.3775439);
annotation.title = @"Custom Callout";

annotation.canShowCallout = YES;
annotation.calloutView = [[MBXCustomCalloutView alloc] init];

[self.mapView addAnnotation:annotation];
[self.mapView showAnnotations:@[annotation] animated:YES];
}
Expand Down Expand Up @@ -699,9 +702,15 @@ - (UIImage *)imageWithText:(NSString *)text backgroundColor:(UIColor *)color
return image;
}

- (BOOL)mapView:(__unused MGLMapView *)mapView annotationCanShowCallout:(__unused id <MGLAnnotation>)annotation
{
return YES;
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id<MGLAnnotation>)annotation {
NSString *title = [(MGLPointAnnotation *)annotation title];
if ( ! title.length)
{
return;
}
NSString *lastTwoCharacters = [title substringFromIndex:title.length - 2];
MGLAnnotationImage *annotationImage = [mapView dequeueReusableAnnotationImageWithIdentifier:lastTwoCharacters];
annotationImage.image = annotationImage.image ? nil : [self imageWithText:lastTwoCharacters backgroundColor:[UIColor grayColor]];
}

- (CGFloat)mapView:(__unused MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation
Expand Down Expand Up @@ -748,35 +757,35 @@ - (void)mapView:(__unused MGLMapView *)mapView didChangeUserTrackingMode:(MGLUse
}];
}

- (UIView<MGLCalloutView> *)mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation
{
if ([annotation respondsToSelector:@selector(title)]
&& [annotation isKindOfClass:[MBXCustomCalloutAnnotation class]])
{
MBXCustomCalloutView *calloutView = [[MBXCustomCalloutView alloc] init];
calloutView.representedObject = annotation;
return calloutView;
}
return nil;
}

- (UIView *)mapView:(__unused MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(__unused id<MGLAnnotation>)annotation
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectZero;
[button setTitle:@"Left" forState:UIControlStateNormal];
[button sizeToFit];
return button;
}

- (UIView *)mapView:(__unused MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(__unused id<MGLAnnotation>)annotation
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectZero;
[button setTitle:@"Right" forState:UIControlStateNormal];
[button sizeToFit];
return button;
}
//- (UIView<MGLCalloutView> *)mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation
//{
// if ([annotation respondsToSelector:@selector(title)]
// && [annotation isKindOfClass:[MBXCustomCalloutAnnotation class]])
// {
// MBXCustomCalloutView *calloutView = [[MBXCustomCalloutView alloc] init];
// calloutView.representedObject = annotation;
// return calloutView;
// }
// return nil;
//}
//
//- (UIView *)mapView:(__unused MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(__unused id<MGLAnnotation>)annotation
//{
// UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
// button.frame = CGRectZero;
// [button setTitle:@"Left" forState:UIControlStateNormal];
// [button sizeToFit];
// return button;
//}
//
//- (UIView *)mapView:(__unused MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(__unused id<MGLAnnotation>)annotation
//{
// UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
// button.frame = CGRectZero;
// [button setTitle:@"Right" forState:UIControlStateNormal];
// [button sizeToFit];
// return button;
//}

- (void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id <MGLAnnotation>)annotation
{
Expand Down
23 changes: 2 additions & 21 deletions platform/ios/ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */; };
9686D6051CDAC6A200B6FA7B /* MBXCustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC9671CB6C6B7006E619F /* MBXCustomCalloutView.m */; };
DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC9671CB6C6B7006E619F /* MBXCustomCalloutView.m */; };
DA1DC96B1CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC9691CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m */; };
DA1DC9701CB6C6CE006E619F /* points.geojson in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC96C1CB6C6CE006E619F /* points.geojson */; };
DA1DC9711CB6C6CE006E619F /* polyline.geojson in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC96D1CB6C6CE006E619F /* polyline.geojson */; };
Expand Down Expand Up @@ -153,8 +153,6 @@
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848811CBB033F00AB86E3 /* FABKitProtocol.h */; };
DA8848861CBB033F00AB86E3 /* Fabric+FABKits.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848821CBB033F00AB86E3 /* Fabric+FABKits.h */; };
DA8848871CBB033F00AB86E3 /* Fabric.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848831CBB033F00AB86E3 /* Fabric.h */; };
DA88488B1CBB037E00AB86E3 /* SMCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848891CBB037E00AB86E3 /* SMCalloutView.h */; };
DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; };
DA88488E1CBB047F00AB86E3 /* reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = DA88488D1CBB047F00AB86E3 /* reachability.h */; };
DA8848901CBB048E00AB86E3 /* reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488F1CBB048E00AB86E3 /* reachability.m */; };
DA8933A31CCC95B000E68420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA89339F1CCC951200E68420 /* Localizable.strings */; };
Expand Down Expand Up @@ -209,7 +207,6 @@
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */; };
DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */; };
DAA4E4341CBB730400178DFB /* MGLUserLocationAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88484E1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m */; };
DAA4E4351CBB730400178DFB /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; };
DAABF73D1CBC59BB005B1825 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAABF73B1CBC59BB005B1825 /* libmbgl-core.a */; };
DAABF73E1CBC59BB005B1825 /* libmbgl-platform-ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAABF73C1CBC59BB005B1825 /* libmbgl-platform-ios.a */; };
DABCABAC1CB80692000A7C39 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DABCABAB1CB80692000A7C39 /* main.m */; };
Expand Down Expand Up @@ -476,8 +473,6 @@
DA8848811CBB033F00AB86E3 /* FABKitProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FABKitProtocol.h; sourceTree = "<group>"; };
DA8848821CBB033F00AB86E3 /* Fabric+FABKits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Fabric+FABKits.h"; sourceTree = "<group>"; };
DA8848831CBB033F00AB86E3 /* Fabric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fabric.h; sourceTree = "<group>"; };
DA8848891CBB037E00AB86E3 /* SMCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMCalloutView.h; sourceTree = "<group>"; };
DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMCalloutView.m; sourceTree = "<group>"; };
DA88488D1CBB047F00AB86E3 /* reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reachability.h; path = ../../include/mbgl/platform/darwin/reachability.h; sourceTree = "<group>"; };
DA88488F1CBB048E00AB86E3 /* reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = reachability.m; path = src/reachability.m; sourceTree = "<group>"; };
DA8933A01CCC951200E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -734,7 +729,6 @@
DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */,
DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */,
DA88487F1CBB033F00AB86E3 /* Fabric */,
DA8848881CBB036000AB86E3 /* SMCalloutView */,
);
name = Kit;
path = src;
Expand Down Expand Up @@ -775,16 +769,6 @@
path = ../vendor/Fabric;
sourceTree = "<group>";
};
DA8848881CBB036000AB86E3 /* SMCalloutView */ = {
isa = PBXGroup;
children = (
DA8848891CBB037E00AB86E3 /* SMCalloutView.h */,
DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */,
);
name = SMCalloutView;
path = ../vendor/SMCalloutView;
sourceTree = "<group>";
};
DA8848911CBB049300AB86E3 /* reachability */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1006,7 +990,6 @@
DA35A29E1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
DA8847F71CBAFA5100AB86E3 /* MGLOverlay.h in Headers */,
DA35A2B11CCA141D00E826B2 /* MGLCompassDirectionFormatter.h in Headers */,
DA88488B1CBB037E00AB86E3 /* SMCalloutView.h in Headers */,
DA8847FE1CBAFA5100AB86E3 /* MGLTypes.h in Headers */,
DA8847F11CBAFA5100AB86E3 /* MGLGeometry.h in Headers */,
DA8848221CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h in Headers */,
Expand Down Expand Up @@ -1361,9 +1344,9 @@
DA1DC9971CB6E046006E619F /* main.m in Sources */,
DA1DC9991CB6E054006E619F /* MBXAppDelegate.m in Sources */,
DA1DC96B1CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m in Sources */,
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */,
DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */,
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */,
9686D6051CDAC6A200B6FA7B /* MBXCustomCalloutView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1396,7 +1379,6 @@
DA8848251CBAFA6200AB86E3 /* MGLPointAnnotation.m in Sources */,
DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */,
DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */,
DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */,
DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */,
DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */,
DA8848901CBB048E00AB86E3 /* reachability.m in Sources */,
Expand Down Expand Up @@ -1438,7 +1420,6 @@
DAA4E42E1CBB730400178DFB /* MGLAPIClient.m in Sources */,
DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */,
DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */,
DAA4E4351CBB730400178DFB /* SMCalloutView.m in Sources */,
DA35A2B91CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */,
DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */,
DAA4E4251CBB730400178DFB /* MGLShape.m in Sources */,
Expand Down
Loading