Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Custom callout: stay open during panning (and some refactoring) #108

Merged
merged 6 commits into from
Aug 21, 2017
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
20 changes: 17 additions & 3 deletions Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -746,13 +746,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ExamplesTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
22AEEA788A5D2A11DF9F9032 /* [CP] Copy Pods Resources */ = {
Expand Down Expand Up @@ -806,9 +809,14 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Examples/Pods-Examples-frameworks.sh",
"${PODS_ROOT}/Mapbox-iOS-SDK-symbols/dynamic/Mapbox.framework",
"${PODS_ROOT}/Mapbox-iOS-SDK-symbols/dynamic/Mapbox.framework.dSYM",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework",
"${DWARF_DSYM_FOLDER_PATH}/Mapbox.framework.dSYM",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand All @@ -821,13 +829,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ExamplesUITests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
964CB5161E445964004549EA /* Insert Mapbox Access Token */ = {
Expand Down Expand Up @@ -880,13 +891,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Examples-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand Down
21 changes: 20 additions & 1 deletion Examples/ObjectiveC/CustomCalloutView.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ @implementation CustomCalloutView {
__unused UIView *_leftAccessoryView;/* unused */
__unused UIView *_rightAccessoryView;/* unused */
__weak id <MGLCalloutViewDelegate> _delegate;
BOOL _dismissesAutomatically;
BOOL _anchoredToAnnotation;
}

@synthesize representedObject = _representedObject;
@synthesize leftAccessoryView = _leftAccessoryView;/* unused */
@synthesize rightAccessoryView = _rightAccessoryView;/* unused */
@synthesize delegate = _delegate;
@synthesize anchoredToAnnotation = _anchoredToAnnotation;
@synthesize dismissesAutomatically = _dismissesAutomatically;

- (instancetype)initWithFrame:(CGRect)frame
{
Expand Down Expand Up @@ -106,6 +110,21 @@ - (void)dismissCalloutAnimated:(BOOL)animated
}
}

// Allow the callout to remain open during panning.
- (BOOL)dismissesAutomatically {
return NO;
}

- (BOOL)isAnchoredToAnnotation {
return YES;
}

// https://github.com/mapbox/mapbox-gl-native/issues/9228
- (void)setCenter:(CGPoint)center {
center.y = center.y - CGRectGetMidY(self.bounds);
[super setCenter:center];
}

#pragma mark - Callout interaction handlers

- (BOOL)isCalloutTappable
Expand Down Expand Up @@ -139,7 +158,7 @@ - (void)drawRect:(CGRect)rect

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;
CGFloat heightWithoutTip = rect.size.height - tipHeight - 1;

CGContextRef currentContext = UIGraphicsGetCurrentContext();

Expand Down
33 changes: 15 additions & 18 deletions Examples/ObjectiveC/CustomCalloutViewExample.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,43 @@ - (void)viewDidLoad {
mapView.tintColor = [UIColor darkGrayColor];
[self.view addSubview:mapView];

// Set the map view‘s delegate property
// Set the map view‘s delegate property.
mapView.delegate = self;

// Initialize and add the marker annotation
// Initialize and add the marker annotation.
MGLPointAnnotation *marker = [[MGLPointAnnotation alloc] init];
marker.coordinate = CLLocationCoordinate2DMake(0, 0);
marker.title = @"Hello world!";

// This custom callout example does not implement subtitles
// This custom callout example does not implement subtitles.
//marker.subtitle = @"Welcome to my marker";

// Add marker to the map
// Add the annotation to the map.
[mapView addAnnotation:marker];

// Select the annotation so the callout will appear.
[mapView selectAnnotation:marker animated:NO];
}

- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation {
// Always allow callouts to popup when annotations are tapped
return YES;
// Only show callouts for `Hello world!` annotation.
return [annotation respondsToSelector:@selector(title)] && [annotation.title isEqualToString:@"Hello world!"];
}

- (UIView<MGLCalloutView> *)mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation
{
// Only show callouts for `Hello world!` annotation
if ([annotation respondsToSelector:@selector(title)]
&& [annotation.title isEqualToString:@"Hello world!"])
{
// Instantiate and return our custom callout view
CustomCalloutView *calloutView = [[CustomCalloutView alloc] init];
calloutView.representedObject = annotation;
return calloutView;
}
return nil;
// Instantiate and return our custom callout view.
CustomCalloutView *calloutView = [[CustomCalloutView alloc] init];
calloutView.representedObject = annotation;
return calloutView;
}

- (void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id<MGLAnnotation>)annotation
{
// Optionally handle taps on the callout
// Optionally handle taps on the callout.
NSLog(@"Tapped the callout for: %@", annotation);

// Hide the callout
// Hide the callout.
[mapView deselectAnnotation:annotation animated:YES];
}

Expand Down
26 changes: 20 additions & 6 deletions Examples/Swift/CustomCalloutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,25 @@ import Mapbox

class CustomCalloutView: UIView, MGLCalloutView {
var representedObject: MGLAnnotation

// Lazy initialization of optional vars for protocols causes segmentation fault: 11s in Swift 3.0. https://bugs.swift.org/browse/SR-1825

var leftAccessoryView = UIView() /* unused */
var rightAccessoryView = UIView() /* unused */

// Allow the callout to remain open during panning.
let dismissesAutomatically: Bool = false
let isAnchoredToAnnotation: Bool = true

// https://github.com/mapbox/mapbox-gl-native/issues/9228
override var center: CGPoint {
set {
var newCenter = newValue
newCenter.y = newCenter.y - bounds.midY
super.center = newCenter
}
get {
return super.center
}
}

lazy var leftAccessoryView = UIView() /* unused */
lazy var rightAccessoryView = UIView() /* unused */

weak var delegate: MGLCalloutViewDelegate?

Expand Down Expand Up @@ -110,7 +124,7 @@ class CustomCalloutView: UIView, MGLCalloutView {

let tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0)
let tipBottom = CGPoint(x: rect.origin.x + (rect.size.width / 2.0), y: rect.origin.y + rect.size.height)
let heightWithoutTip = rect.size.height - tipHeight
let heightWithoutTip = rect.size.height - tipHeight - 1

let currentContext = UIGraphicsGetCurrentContext()!

Expand Down
16 changes: 7 additions & 9 deletions Examples/Swift/CustomCalloutViewExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@ class CustomCalloutViewExample_Swift: UIViewController, MGLMapViewDelegate {

// Add marker to the map.
mapView.addAnnotation(marker)

// Select the annotation so the callout will appear.
mapView.selectAnnotation(marker, animated: false)
}

func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
// Always allow callouts to popup when annotations are tapped.
return true
// Only show callouts for `Hello world!` annotation.
return annotation.responds(to: #selector(getter: MGLAnnotation.title)) && annotation.title! == "Hello world!"
}

func mapView(_ mapView: MGLMapView, calloutViewFor annotation: MGLAnnotation) -> MGLCalloutView? {
// Only show callouts for `Hello world!` annotation.
if annotation.responds(to: #selector(getter: MGLAnnotation.title)) && annotation.title! == "Hello world!" {
// Instantiate and return our custom callout view.
return CustomCalloutView(representedObject: annotation)
}

return nil
// Instantiate and return our custom callout view.
return CustomCalloutView(representedObject: annotation)
}

func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation) {
Expand Down
2 changes: 1 addition & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 506c2d22b088dad61b80255a5b4d3b2ae0d68063

COCOAPODS: 1.2.1
COCOAPODS: 1.3.1