diff options
-rw-r--r-- | gyp/platform-ios.gypi | 6 | ||||
-rw-r--r-- | include/mbgl/ios/MGLCalloutView.h | 67 | ||||
-rw-r--r-- | include/mbgl/ios/MGLCalloutViewProtocol.h | 35 | ||||
-rw-r--r-- | include/mbgl/ios/MGLMapView.h | 10 | ||||
-rw-r--r-- | include/mbgl/ios/Mapbox.h | 2 | ||||
-rw-r--r-- | ios/app/MBXCustomCalloutView.h | 12 | ||||
-rw-r--r-- | ios/app/MBXCustomCalloutView.m | 21 | ||||
-rw-r--r-- | ios/app/MBXViewController.mm | 6 | ||||
-rw-r--r-- | platform/ios/src/MGLCalloutView.h | 6 | ||||
-rw-r--r-- | platform/ios/src/MGLCalloutView.m | 5 | ||||
-rw-r--r-- | platform/ios/src/MGLCompactCalloutView.h | 11 | ||||
-rw-r--r-- | platform/ios/src/MGLCompactCalloutView.m | 31 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 21 |
13 files changed, 151 insertions, 82 deletions
diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index e3e2758128..1a36cf046d 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -68,9 +68,9 @@ '../include/mbgl/ios/MGLAnnotationImage.h', '../platform/ios/src/MGLAnnotationImage_Private.h', '../platform/ios/src/MGLAnnotationImage.m', - '../include/mbgl/ios/MGLCalloutViewProtocol.h', - '../platform/ios/src/MGLCalloutView.h', - '../platform/ios/src/MGLCalloutView.m', + '../include/mbgl/ios/MGLCalloutView.h', + '../platform/ios/src/MGLCompactCalloutView.h', + '../platform/ios/src/MGLCompactCalloutView.m', '../platform/ios/src/MGLCategoryLoader.h', '../platform/ios/src/MGLCategoryLoader.m', '../platform/ios/src/NSBundle+MGLAdditions.h', diff --git a/include/mbgl/ios/MGLCalloutView.h b/include/mbgl/ios/MGLCalloutView.h new file mode 100644 index 0000000000..8e72ee9d68 --- /dev/null +++ b/include/mbgl/ios/MGLCalloutView.h @@ -0,0 +1,67 @@ +#import <Foundation/Foundation.h> + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLCalloutViewDelegate; +@protocol MGLAnnotation; + +/** + A protocol for a `UIView` subclass that displays information about a selected annotation near that annotation. + */ +@protocol MGLCalloutView <NSObject> + +/** + An object conforming to the `MGLAnnotation` protocol whose details this callout view displays. + */ +@property (nonatomic, strong) id <MGLAnnotation> representedObject; + +/** + A view that the user may tap to perform an action. This view is conventionally positioned on the left side of the callout view. + */ +@property (nonatomic, strong) UIView *leftAccessoryView; + +/** + A view that the user may tap to perform an action. This view is conventionally positioned on the right side of the callout view. + */ +@property (nonatomic, strong) UIView *rightAccessoryView; + +/** + An object conforming to the `MGLCalloutViewDelegate` method that receives messages related to the callout view’s interactive subviews. + */ +@property (nonatomic, weak) id<MGLCalloutViewDelegate> delegate; + +/** + Presents a callout view by adding it to `inView` and pointing at the given rect of `inView`’s bounds. Constrains the callout to the bounds of the given view. + */ +- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated; + +/** + Dismisses the callout view. + */ +- (void)dismissCalloutAnimated:(BOOL)animated; + +@end + +/** + The MGLCalloutViewDelegate protocol defines a set of optional methods that you can use to receive messages from an object that conforms to the MGLCalloutView protocol. The callout view uses these methods to inform the delegate that the user has interacted with the the callout view. + */ +@protocol MGLCalloutViewDelegate <NSObject> + +@optional +/** + Returns a Boolean value indicating whether the entire callout view “highlights” when tapped. The default value is `YES`, which means the callout view highlights when tapped. + + The return value of this method is ignored unless the delegate also responds to the `-calloutViewTapped` method. + */ +- (BOOL)calloutViewShouldHighlight:(UIView<MGLCalloutView> *)calloutView; + +/** + Tells the delegate that the callout view has been tapped. + */ +- (void)calloutViewTapped:(UIView<MGLCalloutView> *)calloutView; + +@end + +NS_ASSUME_NONNULL_END
\ No newline at end of file diff --git a/include/mbgl/ios/MGLCalloutViewProtocol.h b/include/mbgl/ios/MGLCalloutViewProtocol.h deleted file mode 100644 index 590a298d71..0000000000 --- a/include/mbgl/ios/MGLCalloutViewProtocol.h +++ /dev/null @@ -1,35 +0,0 @@ -#import <Foundation/Foundation.h> - -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol MGLCalloutViewDelegate; - -@protocol MGLCalloutViewProtocol <NSObject> - -@property (nonatomic, copy) NSString *title, *subtitle; -@property (nonatomic, strong) UIView *leftAccessoryView, *rightAccessoryView; -@property (nonatomic, weak) id<MGLCalloutViewDelegate> delegate; - -// Presents a callout view by adding it to "inView" and pointing at the given rect of inView's bounds. -// Constrains the callout to the bounds of the given view. -- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated; - -- (void)dismissCalloutAnimated:(BOOL)animated; - -@end - - -@protocol MGLCalloutViewDelegate <NSObject> - -@optional -// Controls whether the callout "highlights" when pressed. default YES. You must also respond to `-calloutViewClicked` below. -- (BOOL)calloutViewShouldHighlight:(UIView<MGLCalloutViewProtocol> *)calloutView; - -// Called when the callout view is clicked. -- (void)calloutViewClicked:(UIView<MGLCalloutViewProtocol> *)calloutView; - -@end - -NS_ASSUME_NONNULL_END
\ No newline at end of file diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 589e62a2f9..8a5ebef2a4 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol MGLMapViewDelegate; @protocol MGLAnnotation; @protocol MGLOverlay; -@protocol MGLCalloutViewProtocol; +@protocol MGLCalloutView; /** An interactive, customizable map view with an interface similar to the one @@ -963,15 +963,15 @@ IB_DESIGNABLE - (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation; /** - Returns a custom callout view to display for the specified annotation. + Returns a callout view to display for the specified annotation. - If the method is present in the delegate, it must return a new instance of a view dedicated to display the callout bubble. It will be configured by the map view. + If this method is present in the delegate, it must return a new instance of a view dedicated to display the callout bubble. It will be configured by the map view. If this method is not present, or if it returns `nil`, a standard, two-line, bubble-like callout view is displayed by default. @param mapView The map view that requested the callout view. @param annotation The object representing the annotation. - @return A view following the MGLCalloutView protocol. + @return A view conforming to the `MGLCalloutView` protocol, or `nil` to use the default callout view. */ -- (nullable UIView <MGLCalloutViewProtocol> *)mapView:(MGLMapView *)mapView customCalloutViewForAnnotation:(id <MGLAnnotation>)annotation; +- (nullable UIView <MGLCalloutView> *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id <MGLAnnotation>)annotation; /** Returns the view to display on the left side of the standard callout bubble. diff --git a/include/mbgl/ios/Mapbox.h b/include/mbgl/ios/Mapbox.h index 70eebeeab4..fd4f532a40 100644 --- a/include/mbgl/ios/Mapbox.h +++ b/include/mbgl/ios/Mapbox.h @@ -1,7 +1,7 @@ #import "MGLAccountManager.h" #import "MGLAnnotation.h" #import "MGLAnnotationImage.h" -#import "MGLCalloutViewProtocol.h" +#import "MGLCalloutView.h" #import "MGLGeometry.h" #import "MGLMapCamera.h" #import "MGLMapView.h" diff --git a/ios/app/MBXCustomCalloutView.h b/ios/app/MBXCustomCalloutView.h index 43dfac414c..7f0a61bae3 100644 --- a/ios/app/MBXCustomCalloutView.h +++ b/ios/app/MBXCustomCalloutView.h @@ -1,16 +1,10 @@ #import <UIKit/UIKit.h> -#import <mbgl/ios/MGLCalloutViewProtocol.h> +#import <mbgl/ios/MGLCalloutView.h> -/* +/** * 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 <MGLCalloutViewProtocol> - -@property (nonatomic, copy) NSString *title, *subtitle; -@property (nonatomic, strong) UIView *leftAccessoryView, *rightAccessoryView; -@property (nonatomic, weak) id<MGLCalloutViewDelegate> delegate; - +@interface MBXCustomCalloutView : UIView <MGLCalloutView> @end diff --git a/ios/app/MBXCustomCalloutView.m b/ios/app/MBXCustomCalloutView.m index fa83dc6027..0bbb9d99ed 100644 --- a/ios/app/MBXCustomCalloutView.m +++ b/ios/app/MBXCustomCalloutView.m @@ -1,5 +1,7 @@ #import "MBXCustomCalloutView.h" +#import <mbgl/darwin/MGLAnnotation.h> + static CGFloat const tipHeight = 10.0; static CGFloat const tipWidth = 10.0; @@ -9,7 +11,17 @@ static CGFloat const tipWidth = 10.0; @end -@implementation MBXCustomCalloutView +@implementation MBXCustomCalloutView { + id <MGLAnnotation> _representedObject; + UIView *_leftAccessoryView; + UIView *_rightAccessoryView; + __weak id <MGLCalloutViewDelegate> _delegate; +} + +@synthesize representedObject = _representedObject; +@synthesize leftAccessoryView = _leftAccessoryView; +@synthesize rightAccessoryView = _rightAccessoryView; +@synthesize delegate = _delegate; - (instancetype)initWithFrame:(CGRect)frame { @@ -32,8 +44,11 @@ static CGFloat const tipWidth = 10.0; { [view addSubview:self]; // prepare title label - self.mainLabel.text = self.title; - [self.mainLabel sizeToFit]; + if ([self.representedObject respondsToSelector:@selector(title)]) + { + self.mainLabel.text = self.representedObject.title; + [self.mainLabel sizeToFit]; + } // prepare our frame CGFloat frameWidth = self.mainLabel.bounds.size.width; CGFloat frameHeight = self.mainLabel.bounds.size.height * 2.0; diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index e67003b391..57817d752b 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -153,7 +153,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { @"Add 10,000 Points", @"Add Test Shapes", @"Start World Tour", - @"Add 1 custom Point", + @"Add Custom Callout Point", @"Remove Annotations", @"Toggle Custom Style Layer", nil]; @@ -599,13 +599,13 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { }]; } -- (UIView<MGLCalloutViewProtocol> *)mapView:(__unused MGLMapView *)mapView customCalloutViewForAnnotation:(id<MGLAnnotation>)annotation +- (UIView<MGLCalloutView> *)mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation { if ([annotation respondsToSelector:@selector(title)] && [annotation.title isEqualToString:kCustomCalloutTitle]) { MBXCustomCalloutView *calloutView = [[MBXCustomCalloutView alloc] init]; - calloutView.title = annotation.title; + calloutView.representedObject = annotation; return calloutView; } return nil; diff --git a/platform/ios/src/MGLCalloutView.h b/platform/ios/src/MGLCalloutView.h deleted file mode 100644 index aa5cb95b57..0000000000 --- a/platform/ios/src/MGLCalloutView.h +++ /dev/null @@ -1,6 +0,0 @@ -#import "SMCalloutView.h" -#import "MGLCalloutViewProtocol.h" - -@interface MGLCalloutView : SMCalloutView <MGLCalloutViewProtocol> - -@end diff --git a/platform/ios/src/MGLCalloutView.m b/platform/ios/src/MGLCalloutView.m deleted file mode 100644 index 8fc7cdc08d..0000000000 --- a/platform/ios/src/MGLCalloutView.m +++ /dev/null @@ -1,5 +0,0 @@ -#import "MGLCalloutView.h" - -@implementation MGLCalloutView - -@end diff --git a/platform/ios/src/MGLCompactCalloutView.h b/platform/ios/src/MGLCompactCalloutView.h new file mode 100644 index 0000000000..5f8edd921f --- /dev/null +++ b/platform/ios/src/MGLCompactCalloutView.h @@ -0,0 +1,11 @@ +#import "SMCalloutView.h" +#import "MGLCalloutView.h" + +/** + A concrete implementation of `MGLCalloutView` based on [SMCalloutView](https://github.com/nfarina/calloutview). This callout view displays the represented annotation’s title, subtitle, and accessory views in a compact, two-line layout. + */ +@interface MGLCompactCalloutView : SMCalloutView <MGLCalloutView> + ++ (instancetype)platformCalloutView; + +@end diff --git a/platform/ios/src/MGLCompactCalloutView.m b/platform/ios/src/MGLCompactCalloutView.m new file mode 100644 index 0000000000..49812c51a4 --- /dev/null +++ b/platform/ios/src/MGLCompactCalloutView.m @@ -0,0 +1,31 @@ +#import "MGLCompactCalloutView.h" + +#import "MGLAnnotation.h" + +@implementation MGLCompactCalloutView +{ + id <MGLAnnotation> _representedObject; +} + +@synthesize representedObject = _representedObject; + ++ (instancetype)platformCalloutView +{ + return [[self alloc] init]; +} + +- (void)setRepresentedObject:(id <MGLAnnotation>)representedObject +{ + _representedObject = representedObject; + + if ([representedObject respondsToSelector:@selector(title)]) + { + self.title = representedObject.title; + } + if ([representedObject respondsToSelector:@selector(subtitle)]) + { + self.subtitle = representedObject.subtitle; + } +} + +@end diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index ce42fefe3f..c0909f873d 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -39,7 +39,7 @@ #import "MGLAccountManager_Private.h" #import "MGLAnnotationImage_Private.h" #import "MGLMapboxEvents.h" -#import "MGLCalloutView.h" +#import "MGLCompactCalloutView.h" #import <algorithm> #import <cstdlib> @@ -138,7 +138,7 @@ public: /// Mapping from reusable identifiers to annotation images. @property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier; /// Currently shown popover representing the selected annotation. -@property (nonatomic) UIView<MGLCalloutViewProtocol> *calloutViewForSelectedAnnotation; +@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation; @property (nonatomic) MGLUserLocationAnnotationView *userLocationAnnotationView; @property (nonatomic) CLLocationManager *locationManager; @property (nonatomic) CGPoint centerPoint; @@ -1341,12 +1341,12 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) } } -- (BOOL)calloutViewShouldHighlight:(__unused MGLCalloutView *)calloutView +- (BOOL)calloutViewShouldHighlight:(__unused MGLCompactCalloutView *)calloutView { return [self.delegate respondsToSelector:@selector(mapView:tapOnCalloutForAnnotation:)]; } -- (void)calloutViewClicked:(__unused MGLCalloutView *)calloutView +- (void)calloutViewTapped:(__unused MGLCompactCalloutView *)calloutView { if ([self.delegate respondsToSelector:@selector(mapView:tapOnCalloutForAnnotation:)]) { @@ -2514,9 +2514,9 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) [self.delegate mapView:self annotationCanShowCallout:annotation]) { // build the callout - if ([self.delegate respondsToSelector:@selector(mapView:customCalloutViewForAnnotation:)]) + if ([self.delegate respondsToSelector:@selector(mapView:calloutViewForAnnotation:)]) { - self.calloutViewForSelectedAnnotation = [self.delegate mapView:self customCalloutViewForAnnotation:annotation]; + self.calloutViewForSelectedAnnotation = [self.delegate mapView:self calloutViewForAnnotation:annotation]; } if (!self.calloutViewForSelectedAnnotation) { @@ -2576,13 +2576,10 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration) } } -- (MGLCalloutView *)calloutViewForAnnotation:(id <MGLAnnotation>)annotation +- (MGLCompactCalloutView *)calloutViewForAnnotation:(id <MGLAnnotation>)annotation { - MGLCalloutView *calloutView = (MGLCalloutView *)[MGLCalloutView platformCalloutView]; - - if ([annotation respondsToSelector:@selector(title)]) calloutView.title = annotation.title; - if ([annotation respondsToSelector:@selector(subtitle)]) calloutView.subtitle = annotation.subtitle; - + MGLCompactCalloutView *calloutView = [MGLCompactCalloutView platformCalloutView]; + calloutView.representedObject = annotation; calloutView.tintColor = self.tintColor; return calloutView; |