Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for custom annotation views #421

Merged
merged 5 commits into from
Sep 27, 2016
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
2 changes: 2 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { MapView } from 'react-native-mapbox-gl';
| `contentInset` | `array` | Optional | Change the padding of the viewport of the map. Offset is in pixels. `[top, right, bottom, left]` `[0, 0, 0, 0]` |
| `style` | React styles | Optional | Styles the actual map view container | N/A |
| `debugActive` | `boolean` | Optional | Turns on debug mode. | `false` |
| `children` | `array` | Optional | An array of custom Annotation views (iOS only). You must import Annotation view from the component and put your custom React Native view inside | null |


## Callback props

Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import cloneDeep from 'lodash/cloneDeep';
import clone from 'lodash/clone';
import isEqual from 'lodash/isEqual';
import Annotation from './Annotation';

const { MapboxGLManager } = NativeModules;
const { mapStyles, userTrackingMode, userLocationVerticalAlignment, unknownResourceCount } = MapboxGLManager;
Expand Down Expand Up @@ -438,6 +439,7 @@ const MapboxGLView = requireNativeComponent('RCTMapboxGL', MapView, {

const Mapbox = {
MapView,
Annotation,
mapStyles, userTrackingMode, userLocationVerticalAlignment, unknownResourceCount,
getMetricsEnabled, setMetricsEnabled,
setAccessToken,
Expand Down
12 changes: 12 additions & 0 deletions ios/RCTMapboxGL.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
874C0C441D9436D80034AF3F /* RCTMapboxAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 874C0C401D9436D80034AF3F /* RCTMapboxAnnotation.m */; };
874C0C451D9436D80034AF3F /* RCTMapboxAnnotationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 874C0C421D9436D80034AF3F /* RCTMapboxAnnotationManager.m */; };
C167F89C1D18112B007C7A42 /* RCTMapboxGLConversions.m in Sources */ = {isa = PBXBuildFile; fileRef = C167F89B1D18112B007C7A42 /* RCTMapboxGLConversions.m */; };
C5DBB3441AF2EF2B00E611A9 /* RCTMapboxGL.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C5DBB3431AF2EF2B00E611A9 /* RCTMapboxGL.h */; };
C5DBB3461AF2EF2B00E611A9 /* RCTMapboxGL.m in Sources */ = {isa = PBXBuildFile; fileRef = C5DBB3451AF2EF2B00E611A9 /* RCTMapboxGL.m */; };
Expand Down Expand Up @@ -38,6 +40,10 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
874C0C401D9436D80034AF3F /* RCTMapboxAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapboxAnnotation.m; sourceTree = "<group>"; };
874C0C411D9436D80034AF3F /* RCTMapboxAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapboxAnnotation.h; sourceTree = "<group>"; };
874C0C421D9436D80034AF3F /* RCTMapboxAnnotationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapboxAnnotationManager.m; sourceTree = "<group>"; };
874C0C431D9436D80034AF3F /* RCTMapboxAnnotationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapboxAnnotationManager.h; sourceTree = "<group>"; };
C167F89A1D18111F007C7A42 /* RCTMapboxGLConversions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTMapboxGLConversions.h; sourceTree = "<group>"; };
C167F89B1D18112B007C7A42 /* RCTMapboxGLConversions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapboxGLConversions.m; sourceTree = "<group>"; };
C5DBB3401AF2EF2B00E611A9 /* libRCTMapboxGL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTMapboxGL.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -89,6 +95,10 @@
C5DBB3421AF2EF2B00E611A9 /* RCTMapboxGL */ = {
isa = PBXGroup;
children = (
874C0C401D9436D80034AF3F /* RCTMapboxAnnotation.m */,
874C0C411D9436D80034AF3F /* RCTMapboxAnnotation.h */,
874C0C421D9436D80034AF3F /* RCTMapboxAnnotationManager.m */,
874C0C431D9436D80034AF3F /* RCTMapboxAnnotationManager.h */,
C5DBB3431AF2EF2B00E611A9 /* RCTMapboxGL.h */,
C5DBB3451AF2EF2B00E611A9 /* RCTMapboxGL.m */,
C5DBB3641AF2EFB500E611A9 /* RCTMapboxGLManager.h */,
Expand Down Expand Up @@ -206,6 +216,8 @@
C5DBB3461AF2EF2B00E611A9 /* RCTMapboxGL.m in Sources */,
C5DBB3661AF2EFB500E611A9 /* RCTMapboxGLManager.m in Sources */,
C167F89C1D18112B007C7A42 /* RCTMapboxGLConversions.m in Sources */,
874C0C451D9436D80034AF3F /* RCTMapboxAnnotationManager.m in Sources */,
874C0C441D9436D80034AF3F /* RCTMapboxAnnotation.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
41 changes: 41 additions & 0 deletions ios/RCTMapboxGL/RCTMapboxAnnotation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#import "RCTMapboxAnnotation.h"

#import <MapBox/MapBox.h>
#import <UIKit/UIKit.h>

#import "RCTConvert+MapKit.h"
#import "RCTComponent.h"
#import "RCTMapboxGL.h"

@class RCTBridge;

@interface RCTMapboxAnnotation : MGLAnnotationView <MGLAnnotation>

@property (nonatomic, weak, nullable) RCTMapboxGL *map;
@property (nonatomic, weak, nullable) RCTBridge *bridge;
/**
The center point (specified as a map coordinate) of the annotation. (required)
(read-only)
*/
@property (nonatomic) CLLocationCoordinate2D coordinate;

/**
The string containing the annotation’s title.
Although this property is optional, if you support the selection of annotations
in your map view, you are expected to provide this property. This string is
displayed in the callout for the associated annotation.
*/
@property (nonatomic, copy, nullable) NSString *title;

/**
The string containing the annotation’s subtitle.
This string is displayed in the callout for the associated annotation.
*/
@property (nonatomic, copy, nullable) NSString *subtitle;


@end


20 changes: 20 additions & 0 deletions ios/RCTMapboxGL/RCTMapboxAnnotation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTMapboxAnnotation.h"

#import "RCTEventDispatcher.h"
#import "UIView+React.h"
#import "RCTBridge.h"
#import "RCTUtils.h"

@implementation RCTMapboxAnnotation {
}

@end
14 changes: 14 additions & 0 deletions ios/RCTMapboxGL/RCTMapboxAnnotationManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTViewManager.h"

@interface RCTMapboxAnnotationManager : RCTViewManager

@end
41 changes: 41 additions & 0 deletions ios/RCTMapboxGL/RCTMapboxAnnotationManager.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "RCTMapboxAnnotationManager.h"

#import "RCTUIManager.h"
#import "RCTConvert+CoreLocation.h"
#import "UIView+React.h"
#import "RCTMapboxAnnotation.h"

@interface RCTMapboxAnnotationManager () <MGLMapViewDelegate>

@end

@implementation RCTMapboxAnnotationManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
RCTMapboxAnnotation *marker = [[RCTMapboxAnnotation alloc] init];
// UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handleTap:)];
// // setting this to NO allows the parent MapView to continue receiving marker selection events
// tapGestureRecognizer.cancelsTouchesInView = NO;
// [marker addGestureRecognizer:tapGestureRecognizer];
marker.bridge = self.bridge;
return marker;
}


RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_EXPORT_VIEW_PROPERTY(subtitle, NSString)
RCT_EXPORT_VIEW_PROPERTY(coordinate, CLLocationCoordinate2D)

@end
50 changes: 50 additions & 0 deletions ios/RCTMapboxGL/RCTMapboxGL.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import "UIView+React.h"
#import "RCTLog.h"
#import "RCTMapboxGLConversions.h"
#import "RCTMapboxAnnotation.h"

@implementation RCTMapboxGL {
/* Required to publish events */
Expand Down Expand Up @@ -42,6 +43,16 @@ @implementation RCTMapboxGL {
MGLAnnotationVerticalAlignment _userLocationVerticalAlignment;
/* So we don't fire onChangeUserTracking mode when triggered by props */
BOOL _isChangingUserTracking;
// Array to manually track RN subviews
//
// AIRMap implicitly creates subviews that aren't regular RN children
// (SMCalloutView injects an overlay subview), which otherwise confuses RN
// during component re-renders:
// https://github.com/facebook/react-native/blob/v0.16.0/React/Modules/RCTUIManager.m#L657
//
// Implementation based on RCTTextField, another component with indirect children
// https://github.com/facebook/react-native/blob/v0.16.0/Libraries/Text/RCTTextField.m#L20
NSMutableArray<UIView *> *_reactSubviews;
}

// View creation
Expand All @@ -53,6 +64,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
_clipsToBounds = YES;
_finishedLoading = NO;
_annotations = [NSMutableDictionary dictionary];
_reactSubviews = [NSMutableArray array];
}

return self;
Expand Down Expand Up @@ -108,6 +120,10 @@ - (void)createMapIfNeeded
}

[self addSubview:_map];
for (UIView *annotations in _reactSubviews) {
[_map addAnnotation:annotations];
}

[self layoutSubviews];
}

Expand All @@ -122,8 +138,35 @@ - (void)layoutSubviews
[self createMapIfNeeded];
}
_map.frame = self.bounds;
[_map layoutSubviews];
}

// React subviews for custom annotation management
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex {
// Our desired API is to pass up markers/overlays as children to the mapview component.
// This is where we intercept them and do the appropriate underlying mapview action.
if ([subview isKindOfClass:[RCTMapboxAnnotation class]]) {
((RCTMapboxAnnotation *) subview).map = self;
[_map addAnnotation:(id <MGLAnnotation>) subview];
}
[_reactSubviews insertObject:(UIView *)subview atIndex:(NSUInteger) atIndex];
}

- (void)removeReactSubview:(id<RCTComponent>)subview {
// similarly, when the children are being removed we have to do the appropriate
// underlying mapview action here.
if ([subview isKindOfClass:[RCTMapboxAnnotation class]]) {
[_map removeAnnotation:(id<MGLAnnotation>)subview];
}
[_reactSubviews removeObject:(UIView *)subview];
}

- (NSArray<id<RCTComponent>> *)reactSubviews {
return _reactSubviews;
}



// Annotation management

- (void)upsertAnnotation:(RCTMGLAnnotation *) annotation {
Expand Down Expand Up @@ -203,6 +246,13 @@ - (BOOL)mapView:(RCTMapboxGL *)mapView annotationCanShowCallout:(id <MGLAnnotati
return ([title length] != 0 || [subtitle length] != 0);
}

- (nullable MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id <MGLAnnotation>)annotation {
if (![annotation isKindOfClass:[RCTMGLAnnotation class]] ){
return annotation;
}
return nil;
}

- (UIButton *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
{
if ([annotation isKindOfClass:[RCTMGLAnnotation class]]) {
Expand Down