Skip to content

Commit

Permalink
Merge pull request #421 from aksonov/master
Browse files Browse the repository at this point in the history
support for custom annotation views
  • Loading branch information
1ec5 authored Sep 27, 2016
2 parents cdd8039 + f65c96d commit 4ef787d
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 0 deletions.
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

0 comments on commit 4ef787d

Please sign in to comment.