mirror of
https://github.com/status-im/react-native-mapbox-gl.git
synced 2026-08-27 11:01:13 +00:00
Custom annotation views for Android.
This gives feature parity to Custom Annotation Views between iOS and Android. - Add custom marker view and options for mapbox. - Add an implementation for the Annotation class. - Add a MarkerViewAdapater that transforms Annotations into views that get displayed on the map. - Handle adding and removing of children. - Update custom annotation docs.
This commit is contained in:
@@ -43,7 +43,7 @@ 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. Annotation view must have unique id prop defined as well as coordinate | null |
|
||||
| `children` | `array` | Optional | An array of custom Annotation views. See [Custom Annotations](#custom-annotations). | null |
|
||||
|
||||
|
||||
## Callback props
|
||||
@@ -343,6 +343,58 @@ re-rendered.
|
||||
|
||||
See [the example](./example.js#L116) for an illustration of this.
|
||||
|
||||
#### Custom Annotations
|
||||
|
||||
If the default annotations do not offer enough options, you can embed react native
|
||||
view directly onto the map as a custom marker view.
|
||||
|
||||
The children of the `MapView` must be `Annotation` views: `import {Annotation} from 'mapbox-react-native-gl'`.
|
||||
The `Annotation` view has the following required props:
|
||||
|
||||
| Prop | Type | Description |
|
||||
|---|---|---|---|---|
|
||||
| `id`| `string` | Unique identifier for the annotation. |
|
||||
| `coordinate` | ```{latitude: number, longitude: number}``` | Location of the annotation. |
|
||||
|
||||
###### Known Bugs
|
||||
|
||||
1. `Annotation` views do not position correctly unless they have the following style props:
|
||||
`style={{alignItems: 'center', justifyContent: 'center', position: 'absolute'}}`.
|
||||
|
||||
2. React Native views do not work with the regular `onAnnotationTapped` on need to
|
||||
add their own tap handling (e.g. by using a `TouchableHighlight`).
|
||||
|
||||
3. (*Android only*) Adding a view with style `flex: 1` and no `width` or `height` set can cause
|
||||
views to behave a little strangely. It is recommended to add them.
|
||||
|
||||
###### Example
|
||||
|
||||
```
|
||||
<MapView {...MapView props}>
|
||||
<Annotation
|
||||
id="annotation1"
|
||||
coordinate={{latitude: 37.5, longitude: -122.2}}
|
||||
style={{alignItems: 'center', justifyContent: 'center', position: 'absolute'}}
|
||||
>
|
||||
<View style={{width: 100, height: 100, borderWidth: 4, borderColor: 'blue', borderRadius: 50, backgroundColor: 'white', flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
||||
<Text>React View</Text>
|
||||
</View>
|
||||
</Annotation>
|
||||
<Annotation
|
||||
id="annotation2"
|
||||
coordinate={{latitude: 37.55, longitude: -122.25}}
|
||||
style={{alignItems: 'center', justifyContent: 'center', position: 'absolute'}}
|
||||
>
|
||||
<View style={{width: 200, height: 200, borderWidth: 1, borderColor: 'red', borderRadius: 50, backgroundColor: 'white', flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
||||
<Image
|
||||
style={{width: 100, height: 100}}
|
||||
source={{uri: 'some-image-uri'}}
|
||||
/>
|
||||
</View>
|
||||
</Annotation>
|
||||
</MapView>
|
||||
```
|
||||
|
||||
## Mapbox Telemetry (metrics)
|
||||
|
||||
If you hide the attribution button, you need to provide the user with a way to
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
public class RNMGLAnnotationView extends ReactViewGroup {
|
||||
|
||||
private final RNMGLAnnotationViewManager _manager;
|
||||
private String annotationId;
|
||||
private LatLng coordinate;
|
||||
|
||||
public RNMGLAnnotationView(Context context, RNMGLAnnotationViewManager manager) {
|
||||
super(context);
|
||||
this._manager = manager;
|
||||
}
|
||||
|
||||
public LayoutParams getShadowNodeMeasurements() {
|
||||
LayoutShadowNode shadowNode = _manager.getShadowNode();
|
||||
return new LayoutParams(
|
||||
(int)shadowNode.getLayoutWidth(),
|
||||
(int)shadowNode.getLayoutHeight()
|
||||
);
|
||||
}
|
||||
|
||||
public String getAnnotationId() {
|
||||
return annotationId;
|
||||
}
|
||||
|
||||
public void setAnnotationId(String annotationId) {
|
||||
this.annotationId = annotationId;
|
||||
}
|
||||
|
||||
public LatLng getCoordinate() {
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
public void setCoordinate(LatLng coordinate) {
|
||||
this.coordinate = coordinate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by gcole on 2/17/17.
|
||||
*/
|
||||
public class RNMGLAnnotationViewManager extends ViewGroupManager<RNMGLAnnotationView> {
|
||||
private LayoutShadowNode _shadowNode;
|
||||
|
||||
private static final String NAME = "RCTMapboxAnnotation";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RNMGLAnnotationView createViewInstance(ThemedReactContext reactContext) {
|
||||
return new RNMGLAnnotationView(reactContext, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutShadowNode createShadowNodeInstance() {
|
||||
_shadowNode = super.createShadowNodeInstance();
|
||||
return _shadowNode;
|
||||
}
|
||||
|
||||
public LayoutShadowNode getShadowNode() {
|
||||
return _shadowNode;
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
@ReactProp(name = "id")
|
||||
public void setAnnotationId(RNMGLAnnotationView view, String value) {
|
||||
view.setAnnotationId(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "coordinate")
|
||||
public void setCoordinate(RNMGLAnnotationView view, ReadableMap map) {
|
||||
LatLng coordinate = new LatLng();
|
||||
coordinate.setLatitude(map.getDouble("latitude"));
|
||||
coordinate.setLongitude(map.getDouble("longitude"));
|
||||
view.setCoordinate(coordinate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
|
||||
public class RNMGLCustomMarkerView extends MarkerView {
|
||||
|
||||
private String annotationId;
|
||||
|
||||
public RNMGLCustomMarkerView(BaseMarkerViewOptions baseMarkerViewOptions, String annotationId) {
|
||||
super(baseMarkerViewOptions);
|
||||
this.annotationId = annotationId;
|
||||
}
|
||||
|
||||
public String getAnnotationId() {
|
||||
return annotationId;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
public class RNMGLCustomMarkerViewOptions extends BaseMarkerViewOptions<RNMGLCustomMarkerView, RNMGLCustomMarkerViewOptions> {
|
||||
private String annotationId;
|
||||
|
||||
protected RNMGLCustomMarkerViewOptions(Parcel in) {
|
||||
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
|
||||
snippet(in.readString());
|
||||
title(in.readString());
|
||||
flat(in.readByte() != 0);
|
||||
anchor(in.readFloat(), in.readFloat());
|
||||
infoWindowAnchor(in.readFloat(), in.readFloat());
|
||||
rotation(in.readFloat());
|
||||
visible(in.readByte() != 0);
|
||||
alpha(in.readFloat());
|
||||
if (in.readByte() != 0) {
|
||||
// this means we have an icon
|
||||
String iconId = in.readString();
|
||||
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
||||
Icon icon = IconFactory.recreate(iconId, iconBitmap);
|
||||
icon(icon);
|
||||
}
|
||||
annotationId(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RNMGLCustomMarkerViewOptions getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RNMGLCustomMarkerView getMarker() {
|
||||
return new RNMGLCustomMarkerView(this, annotationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(getPosition(), flags);
|
||||
out.writeString(getSnippet());
|
||||
out.writeString(getTitle());
|
||||
out.writeByte((byte) (isFlat() ? 1 : 0));
|
||||
out.writeFloat(getAnchorU());
|
||||
out.writeFloat(getAnchorV());
|
||||
out.writeFloat(getInfoWindowAnchorU());
|
||||
out.writeFloat(getInfoWindowAnchorV());
|
||||
out.writeFloat(getRotation());
|
||||
out.writeByte((byte) (isVisible() ? 1 : 0));
|
||||
out.writeFloat(getAlpha());
|
||||
Icon icon = getIcon();
|
||||
out.writeByte((byte) (icon != null ? 1 : 0));
|
||||
if (icon != null) {
|
||||
out.writeString(getIcon().getId());
|
||||
out.writeParcelable(getIcon().getBitmap(), flags);
|
||||
}
|
||||
out.writeString(annotationId);
|
||||
}
|
||||
|
||||
public RNMGLCustomMarkerViewOptions annotationId(String annotationId) {
|
||||
this.annotationId = annotationId;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<RNMGLCustomMarkerViewOptions> CREATOR
|
||||
= new Parcelable.Creator<RNMGLCustomMarkerViewOptions>() {
|
||||
public RNMGLCustomMarkerViewOptions createFromParcel(Parcel in) {
|
||||
return new RNMGLCustomMarkerViewOptions(in);
|
||||
}
|
||||
|
||||
public RNMGLCustomMarkerViewOptions[] newArray(int size) {
|
||||
return new RNMGLCustomMarkerViewOptions[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
+79
-2
@@ -1,6 +1,8 @@
|
||||
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
@@ -11,9 +13,9 @@ import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.SimpleViewManager;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
@@ -21,20 +23,28 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReactNativeMapboxGLManager extends SimpleViewManager<ReactNativeMapboxGLView> {
|
||||
public class ReactNativeMapboxGLManager extends ViewGroupManager<ReactNativeMapboxGLView> {
|
||||
|
||||
private static final String REACT_CLASS = "RCTMapboxGL";
|
||||
|
||||
private ReactApplicationContext _context;
|
||||
private List<View> _childViews;
|
||||
private Set<ChildListener> _childListeners;
|
||||
|
||||
public ReactNativeMapboxGLManager(ReactApplicationContext context) {
|
||||
super();
|
||||
_context = context;
|
||||
_childViews = new ArrayList<>();
|
||||
_childListeners = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,6 +56,16 @@ public class ReactNativeMapboxGLManager extends SimpleViewManager<ReactNativeMap
|
||||
return _context;
|
||||
}
|
||||
|
||||
public List<RNMGLAnnotationView> getAnnotationViews() {
|
||||
List<RNMGLAnnotationView> annotationViews = new ArrayList<>();
|
||||
for (View view : _childViews) {
|
||||
if (RNMGLAnnotationView.class.equals(view.getClass())) {
|
||||
annotationViews.add((RNMGLAnnotationView) view);
|
||||
}
|
||||
}
|
||||
return annotationViews;
|
||||
}
|
||||
|
||||
// Lifecycle methods
|
||||
|
||||
@Override
|
||||
@@ -82,6 +102,63 @@ public class ReactNativeMapboxGLManager extends SimpleViewManager<ReactNativeMap
|
||||
.build();
|
||||
}
|
||||
|
||||
// Children
|
||||
|
||||
public interface ChildListener {
|
||||
void childAdded(View child);
|
||||
void childRemoved(View child);
|
||||
}
|
||||
|
||||
public void addChildListener(ChildListener listener) {
|
||||
_childListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeChildListener(ChildListener listener) {
|
||||
_childListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(ReactNativeMapboxGLView parent, View child, int index) {
|
||||
_childViews.add(index, child);
|
||||
if (!RNMGLAnnotationView.class.equals(child.getClass())) {
|
||||
super.addView(parent, child, getRealIndex(parent, index));
|
||||
}
|
||||
for (ChildListener listener : _childListeners) {
|
||||
listener.childAdded(child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(ReactNativeMapboxGLView parent) {
|
||||
return _childViews.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildAt(ReactNativeMapboxGLView parent, int index) {
|
||||
return _childViews.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewAt(ReactNativeMapboxGLView parent, int index) {
|
||||
View child = _childViews.remove(index);
|
||||
if (!RNMGLAnnotationView.class.equals(child.getClass())) {
|
||||
super.removeViewAt(parent, getRealIndex(parent, index));
|
||||
}
|
||||
for (ChildListener listener : _childListeners) {
|
||||
listener.childRemoved(child);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRealIndex(ReactNativeMapboxGLView parent, int index) {
|
||||
int annotationViews = 0;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (RNMGLAnnotationView.class.equals(getChildAt(parent, i).getClass())) {
|
||||
annotationViews++;
|
||||
}
|
||||
}
|
||||
return index - annotationViews;
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
@ReactProp(name = "initialZoomLevel")
|
||||
|
||||
+2
-1
@@ -29,7 +29,8 @@ public class ReactNativeMapboxGLPackage implements ReactPackage {
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Arrays.<ViewManager>asList(
|
||||
new ReactNativeMapboxGLManager(reactContext)
|
||||
new ReactNativeMapboxGLManager(reactContext),
|
||||
new RNMGLAnnotationViewManager()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,40 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.location.Location;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
@@ -30,8 +48,14 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -41,7 +65,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
MapboxMap.OnMyBearingTrackingModeChangeListener, MapboxMap.OnMyLocationTrackingModeChangeListener,
|
||||
MapboxMap.OnMyLocationChangeListener,
|
||||
MapboxMap.OnMarkerClickListener, MapboxMap.OnInfoWindowClickListener,
|
||||
MapView.OnMapChangedListener
|
||||
MapView.OnMapChangedListener, ReactNativeMapboxGLManager.ChildListener
|
||||
{
|
||||
|
||||
private MapboxMap _map = null;
|
||||
@@ -70,9 +94,11 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
private boolean _didChangeThrottled = false;
|
||||
private boolean _changeWasAnimated = false;
|
||||
|
||||
private Map<String, Annotation> _annotations = new HashMap();
|
||||
private Map<Long, String> _annotationIdsToName = new HashMap();
|
||||
private Map<String, RNMGLAnnotationOptions> _annotationOptions = new HashMap();
|
||||
private Map<String, Annotation> _annotations = new HashMap<>();
|
||||
private Map<Long, String> _annotationIdsToName = new HashMap<>();
|
||||
private Map<String, RNMGLAnnotationOptions> _annotationOptions = new HashMap<>();
|
||||
private Map<String, MarkerView> _customAnnodationIds = new HashMap<>();
|
||||
private Map<String, RNMGLAnnotationView> _customAnnotationViewMap = new HashMap<>();
|
||||
|
||||
private android.os.Handler _handler;
|
||||
|
||||
@@ -101,6 +127,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
public void onDrop() {
|
||||
if (_mapView == null) { return; }
|
||||
_manager.getContext().removeLifecycleEventListener(this);
|
||||
_manager.removeChildListener(this);
|
||||
if (!_paused) {
|
||||
_paused = true;
|
||||
_mapView.onPause();
|
||||
@@ -131,7 +158,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
private void setupMapView() {
|
||||
_mapOptions.camera(_initialCamera.build());
|
||||
_mapView = new MapView(this.getContext(), _mapOptions);
|
||||
this.addView(_mapView);
|
||||
_manager.addView(this, _mapView, 0);
|
||||
_mapView.addOnMapChangedListener(this);
|
||||
_mapView.onCreate(null);
|
||||
_mapView.getMapAsync(this);
|
||||
@@ -189,7 +216,14 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
_annotations.put(entry.getKey(), annotation);
|
||||
_annotationIdsToName.put(annotation.getId(), entry.getKey());
|
||||
}
|
||||
|
||||
_annotationOptions.clear();
|
||||
|
||||
computeMarkerAnnotations();
|
||||
_manager.addChildListener(this);
|
||||
|
||||
_map.getMarkerViewManager().addMarkerViewAdapter(
|
||||
new RNMGLCustomMarkerViewAdapter(getContext()));
|
||||
}
|
||||
|
||||
private void destroyMapView() {
|
||||
@@ -207,6 +241,52 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
_mapView.onDestroy();
|
||||
}
|
||||
|
||||
// Children
|
||||
|
||||
@Override
|
||||
public void childAdded(View child) {
|
||||
computeMarkerAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childRemoved(View child) {
|
||||
computeMarkerAnnotations();
|
||||
}
|
||||
|
||||
private void computeMarkerAnnotations() {
|
||||
Set<RNMGLAnnotationView> newAnnotationViews = new HashSet<>(_manager.getAnnotationViews());
|
||||
Set<RNMGLAnnotationView> currentViews = new HashSet<>(_customAnnotationViewMap.values());
|
||||
Collection<RNMGLAnnotationView> addedChildren = Sets.difference(newAnnotationViews, currentViews);
|
||||
Collection<RNMGLAnnotationView> removedChildren = Sets.difference(currentViews, newAnnotationViews);
|
||||
|
||||
for (RNMGLAnnotationView annotationView : removedChildren) {
|
||||
_customAnnotationViewMap.remove(annotationView.getAnnotationId());
|
||||
MarkerView markerView = _customAnnodationIds.remove(annotationView.getAnnotationId());
|
||||
_map.removeMarker(markerView);
|
||||
}
|
||||
|
||||
for (RNMGLAnnotationView annotationView : addedChildren) {
|
||||
_customAnnotationViewMap.put(annotationView.getAnnotationId(), annotationView);
|
||||
RNMGLCustomMarkerViewOptions options = new RNMGLCustomMarkerViewOptions()
|
||||
.annotationId(annotationView.getAnnotationId())
|
||||
.position(annotationView.getCoordinate())
|
||||
.flat(true);
|
||||
MarkerView markerView = _map.addMarker(options);
|
||||
_customAnnodationIds.put(annotationView.getAnnotationId(), markerView);
|
||||
}
|
||||
|
||||
// Need a relayout to show custom marker views
|
||||
_handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
_mapView.measure(
|
||||
View.MeasureSpec.makeMeasureSpec(_mapView.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
|
||||
View.MeasureSpec.makeMeasureSpec(_mapView.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
|
||||
_mapView.layout(_mapView.getLeft(), _mapView.getTop(), _mapView.getRight(), _mapView.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
public void setInitialZoomLevel(double value) {
|
||||
@@ -706,4 +786,29 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
if (_map == null) { return; }
|
||||
_map.deselectMarkers();
|
||||
}
|
||||
|
||||
// Custom Marker View Adapter - Adapts a MarkerView to display an custom react native view.
|
||||
|
||||
private class RNMGLCustomMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<RNMGLCustomMarkerView> {
|
||||
|
||||
RNMGLCustomMarkerViewAdapter(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getView(@NonNull RNMGLCustomMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
RNMGLAnnotationView reactView = _customAnnotationViewMap.get(marker.getAnnotationId());
|
||||
ViewGroup.LayoutParams shadowNodeMeasurements = reactView.getShadowNodeMeasurements();
|
||||
|
||||
FrameLayout layout = new FrameLayout(getContext());
|
||||
layout.setLayoutParams(shadowNodeMeasurements);
|
||||
layout.addView(reactView);
|
||||
|
||||
convertView = layout;
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user