Skip to content

Commit

Permalink
[google] refactor AIRGoogleMapMarker to use DummyView (react-native-m…
Browse files Browse the repository at this point in the history
…aps#649)

- DummyView is used to create virtual tree
- Add CustomMarkers example
- Prevent annoying errors from showing up with OS_ACTIVITY_MODE disable, see here facebook/react-native#9921 (comment)
  • Loading branch information
gilbox authored Oct 5, 2016
1 parent f226d90 commit d556597
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 27 deletions.
2 changes: 2 additions & 0 deletions example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import AnimatedMarkers from './examples/AnimatedMarkers';
import Callouts from './examples/Callouts';
import Overlays from './examples/Overlays';
import DefaultMarkers from './examples/DefaultMarkers';
import CustomMarkers from './examples/CustomMarkers';
import CachedMap from './examples/CachedMap';
import LoadingMap from './examples/LoadingMap';
import TakeSnapshot from './examples/TakeSnapshot';
Expand Down Expand Up @@ -129,6 +130,7 @@ class App extends React.Component {
[Callouts, 'Custom Callouts', true],
[Overlays, 'Circles, Polygons, and Polylines', true, '(ios error)'],
[DefaultMarkers, 'Default Markers', true],
[CustomMarkers, 'Custom Markers', true],
[TakeSnapshot, 'Take Snapshot', true, '(incomplete)'],
[CachedMap, 'Cached Map'],
[LoadingMap, 'Map with loading'],
Expand Down
118 changes: 118 additions & 0 deletions example/examples/CustomMarkers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from 'react';
import {
StyleSheet,
View,
Text,
Dimensions,
TouchableOpacity,
} from 'react-native';

import MapView from 'react-native-maps';
import flagPinkImg from './assets/flag-pink.png';

const { width, height } = Dimensions.get('window');

const ASPECT_RATIO = width / height;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
let id = 0;

class CustomMarkers extends React.Component {
constructor(props) {
super(props);

this.state = {
region: {
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
markers: [],
};

this.onMapPress = this.onMapPress.bind(this);
}

onMapPress(e) {
this.setState({
markers: [
...this.state.markers,
{
coordinate: e.nativeEvent.coordinate,
key: `foo${id++}`,
},
],
});
}

render() {
return (
<View style={styles.container}>
<MapView
provider={this.props.provider}
style={styles.map}
initialRegion={this.state.region}
onPress={this.onMapPress}
>
{this.state.markers.map(marker => (
<MapView.Marker
title={marker.key}
image={flagPinkImg}
key={marker.key}
coordinate={marker.coordinate}
/>
))}
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => this.setState({ markers: [] })}
style={styles.bubble}
>
<Text>Tap to create a marker of random color</Text>
</TouchableOpacity>
</View>
</View>
);
}
}

CustomMarkers.propTypes = {
provider: MapView.ProviderPropType,
};

const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
bubble: {
backgroundColor: 'rgba(255,255,255,0.7)',
paddingHorizontal: 18,
paddingVertical: 12,
borderRadius: 20,
},
latlng: {
width: 200,
alignItems: 'stretch',
},
button: {
width: 80,
paddingHorizontal: 12,
alignItems: 'center',
marginHorizontal: 10,
},
buttonContainer: {
flexDirection: 'row',
marginVertical: 20,
backgroundColor: 'transparent',
},
});

module.exports = CustomMarkers;
6 changes: 6 additions & 0 deletions example/ios/AirMapsExplorer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
2166AB351D82EC56007538D7 /* AIRMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB141D82EC56007538D7 /* AIRMapPolylineManager.m */; };
2166AB361D82EC56007538D7 /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB171D82EC56007538D7 /* SMCalloutView.m */; };
2166AB3E1D82EC56007538D7 /* RCTConvert+MoreMapKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB281D82EC56007538D7 /* RCTConvert+MoreMapKit.m */; };
21B248671DA4483D008FCB52 /* DummyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 21B248661DA4483D008FCB52 /* DummyView.m */; };
21D346651D933B8C002BAD8A /* AIRMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D346621D933B8C002BAD8A /* AIRMapUrlTile.m */; };
21D346661D933B8C002BAD8A /* AIRMapUrlTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D346641D933B8C002BAD8A /* AIRMapUrlTileManager.m */; };
21E6570A1D77591400B75EE5 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E657091D77591400B75EE5 /* SystemConfiguration.framework */; };
Expand Down Expand Up @@ -111,6 +112,8 @@
2166AB171D82EC56007538D7 /* SMCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMCalloutView.m; sourceTree = "<group>"; };
2166AB271D82EC56007538D7 /* RCTConvert+MoreMapKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+MoreMapKit.h"; sourceTree = "<group>"; };
2166AB281D82EC56007538D7 /* RCTConvert+MoreMapKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+MoreMapKit.m"; sourceTree = "<group>"; };
21B248661DA4483D008FCB52 /* DummyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DummyView.m; sourceTree = "<group>"; };
21B248681DA44851008FCB52 /* DummyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DummyView.h; sourceTree = "<group>"; };
21D346611D933B8C002BAD8A /* AIRMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTile.h; sourceTree = "<group>"; };
21D346621D933B8C002BAD8A /* AIRMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTile.m; sourceTree = "<group>"; };
21D346631D933B8C002BAD8A /* AIRMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTileManager.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -195,6 +198,8 @@
213CA8E71D89F66A008623EC /* AIRGoogleMapMarker.m */,
213CA8E81D89F66A008623EC /* AIRGoogleMapMarkerManager.h */,
213CA8E91D89F66A008623EC /* AIRGoogleMapMarkerManager.m */,
21B248661DA4483D008FCB52 /* DummyView.m */,
21B248681DA44851008FCB52 /* DummyView.h */,
);
name = AirGoogleMaps;
path = ../../ios/AirGoogleMaps;
Expand Down Expand Up @@ -512,6 +517,7 @@
2166AB301D82EC56007538D7 /* AIRMapMarker.m in Sources */,
2166AB321D82EC56007538D7 /* AIRMapPolygon.m in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
21B248671DA4483D008FCB52 /* DummyView.m in Sources */,
2166AB3E1D82EC56007538D7 /* RCTConvert+MoreMapKit.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
2166AB331D82EC56007538D7 /* AIRMapPolygonManager.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
ReferencedContainer = "container:AirMapsExplorer.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
Expand Down
12 changes: 6 additions & 6 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
PODS:
- GoogleMaps (2.0.1):
- GoogleMaps/Maps (= 2.0.1)
- GoogleMaps/Base (2.0.1)
- GoogleMaps/Maps (2.0.1):
- GoogleMaps/Base (= 2.0.1)
- GoogleMaps (2.1.0):
- GoogleMaps/Maps (= 2.1.0)
- GoogleMaps/Base (2.1.0)
- GoogleMaps/Maps (2.1.0):
- GoogleMaps/Base (= 2.1.0)
- React/Core (0.32.0):
- React/CSSLayout
- React/CSSLayout (0.32.0)
Expand Down Expand Up @@ -45,7 +45,7 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native"

SPEC CHECKSUMS:
GoogleMaps: f09da64fc987c1aa29394567c3cab5a3df83c402
GoogleMaps: 06589b9a38097bce0cd6e90f0fd9b5e4b4a9344c
React: 0245b401173a94a5fba0f440aab3fb2f79b738f3

COCOAPODS: 0.39.0
66 changes: 45 additions & 21 deletions ios/AirGoogleMaps/AIRGoogleMapMarker.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "AIRGoogleMapCallout.h"
#import "RCTImageLoader.h"
#import "RCTUtils.h"
#import "DummyView.h"

CGRect unionRect(CGRect a, CGRect b) {
return CGRectMake(
Expand All @@ -27,6 +28,7 @@ - (id)eventFromMarker:(AIRGMSMarker*)marker;
@implementation AIRGoogleMapMarker {
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
__weak UIImageView *_iconImageView;
UIView *_iconView;
}

- (instancetype)init
Expand All @@ -38,12 +40,28 @@ - (instancetype)init
return self;
}

- (void)layoutSubviews {
float width = 0;
float height = 0;

for (UIView *v in [_iconView subviews]) {

float fw = v.frame.origin.x + v.frame.size.width;
float fh = v.frame.origin.y + v.frame.size.height;

width = MAX(fw, width);
height = MAX(fh, height);
}

[_iconView setFrame:CGRectMake(0, 0, width, height)];
}

- (id)eventFromMarker:(AIRGMSMarker*)marker {

CLLocationCoordinate2D coordinate = marker.position;
CGPoint position = [self.realMarker.map.projection pointForCoordinate:coordinate];

return @{
return @{
@"id": marker.identifier ?: @"unknown",
@"position": @{
@"x": @(position.x),
Expand All @@ -56,27 +74,33 @@ - (id)eventFromMarker:(AIRGMSMarker*)marker {
};
}

- (void)iconViewInsertSubview:(UIView*)subview atIndex:(NSInteger)atIndex {
if (!_realMarker.iconView) {
_iconView = [[UIView alloc] init];
_realMarker.iconView = _iconView;
}
[_iconView insertSubview:subview atIndex:atIndex];
}

- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex {
if ([subview isKindOfClass:[AIRGoogleMapCallout class]]) {
self.calloutView = (AIRGoogleMapCallout *)subview;
} else {
// Custom UIView Marker
// NOTE: Originally I tried creating a new UIView here to encapsulate subview,
// but it would not sizeToFit properly. Not sure why.
[super insertReactSubview:(UIView*)subview atIndex:atIndex];
[self sizeToFit];

// TODO: how to handle this circular reference properly?
_realMarker.iconView = self;
} else { // a child view of the marker
[self iconViewInsertSubview:(UIView*)subview atIndex:atIndex+1];
}
DummyView *dummySubview = [[DummyView alloc] initWithView:(UIView *)subview];
[super insertReactSubview:(UIView*)dummySubview atIndex:atIndex];
}

- (void)removeReactSubview:(id<RCTComponent>)subview {
- (void)removeReactSubview:(id<RCTComponent>)dummySubview {
UIView* subview = ((DummyView*)dummySubview).view;

if ([subview isKindOfClass:[AIRGoogleMapCallout class]]) {
self.calloutView = nil;
} else {
[super removeReactSubview:(UIView*)subview];
[(UIView*)subview removeFromSuperview];
}
[super removeReactSubview:(UIView*)dummySubview];
}

- (void)showCalloutView {
Expand Down Expand Up @@ -151,7 +175,6 @@ - (RCTBubblingEventBlock)onPress {

- (void)setImageSrc:(NSString *)imageSrc
{

_imageSrc = imageSrc;

if (_reloadImageCancellationBlock) {
Expand All @@ -172,11 +195,14 @@ - (void)setImageSrc:(NSString *)imageSrc
}
dispatch_async(dispatch_get_main_queue(), ^{

if (_iconImageView) {
// TODO: doesn't work because image is blank (WHY??)
[_iconImageView setImage:image];
return;
}
// TODO(gil): This way allows different image sizes
if (_iconImageView) [_iconImageView removeFromSuperview];

// ... but this way is more efficient?
// if (_iconImageView) {
// [_iconImageView setImage:image];
// return;
// }

UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

Expand All @@ -197,9 +223,7 @@ - (void)setImageSrc:(NSString *)imageSrc
[self setFrame:selfBounds];

_iconImageView = imageView;

[super insertSubview:imageView atIndex:0];
_realMarker.iconView = self;
[self iconViewInsertSubview:imageView atIndex:0];

// TODO: This could be a prop
//_realMarker.groundAnchor = CGPointMake(0.75, 1);
Expand Down
14 changes: 14 additions & 0 deletions ios/AirGoogleMaps/DummyView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// DummyView.h
// AirMapsExplorer
//
// Created by Gil Birman on 10/4/16.
//

#import <UIKit/UIKit.h>


@interface DummyView : UIView
@property (nonatomic, weak) UIView *view;
- (instancetype)initWithView:(UIView*)view;
@end
19 changes: 19 additions & 0 deletions ios/AirGoogleMaps/DummyView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// DummyView.m
// AirMapsExplorer
//
// Created by Gil Birman on 10/4/16.
//

#import <Foundation/Foundation.h>
#import "DummyView.h"

@implementation DummyView
- (instancetype)initWithView:(UIView*)view
{
if ((self = [super init])) {
self.view = view;
}
return self;
}
@end

0 comments on commit d556597

Please sign in to comment.