Skip to content

Commit 5bd099b

Browse files
authored
feat: mapViewImpl so native code can register custom mapView factory (#3275)
1 parent bad4488 commit 5bd099b

File tree

8 files changed

+116
-18
lines changed

8 files changed

+116
-18
lines changed

android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,22 @@ data class FeatureEntry(val feature: AbstractMapFeature?, val view: View?, var a
195195

196196
}
197197

198+
typealias Factory = (impl: String, ViewGroup) -> MapView?;
199+
public class RNMBXMapViewFactory {
200+
companion object {
201+
var factories = mutableMapOf<String,Factory>();
202+
fun regiser(impl: String, factory: Factory) {
203+
val (impl, options) = impl.split(":",limit=2)
204+
factories.put(impl, factory);
205+
}
206+
207+
fun get(impl: String): Factory? {
208+
val (impl, options) = impl.split(":",limit=2);
209+
return factories.get(impl);
210+
}
211+
}
212+
}
213+
198214
open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapViewManager, options: MapInitOptions?) : FrameLayout(mContext), OnMapClickListener, OnMapLongClickListener, OnLayoutChangeListener {
199215
/**
200216
* `PointAnnotations` are rendered to a canvas, but the React Native `Image` component is
@@ -249,6 +265,8 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
249265
private var wasGestureActive = false
250266
private var isGestureActive = false
251267

268+
var mapViewImpl: String? = null
269+
252270
val mapView: MapView
253271
get() = this.mMapView
254272

@@ -1136,17 +1154,37 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
11361154
const val LOG_TAG = "RNMBXMapView"
11371155
}
11381156

1157+
fun createAndAddMapView(mapViewImpl: String): MapView? {
1158+
RNMBXMapViewFactory.get(mapViewImpl)?.let {
1159+
return it(mapViewImpl, this);
1160+
}
1161+
return null;
1162+
}
1163+
11391164
fun createMapView() : MapView {
1140-
var options: MapInitOptions? = null
1141-
if (surfaceView == false) {
1142-
options = MapInitOptions(context= mContext, textureView= true)
1165+
var created = false;
1166+
mapViewImpl?.also {impl ->
1167+
createAndAddMapView(impl)?.let { mapView ->
1168+
mMapView = mapView
1169+
created = true;
1170+
}
11431171
}
1144-
val mapView = if (options != null) MapView(mContext, options) else MapView(mContext)
1145-
mMapView = mapView
1172+
if (!created) {
1173+
var options: MapInitOptions? = null
1174+
if (surfaceView == false) {
1175+
options = MapInitOptions(context = mContext, textureView = true)
1176+
}
1177+
val mapView = if (options != null) MapView(mContext, options) else MapView(mContext)
1178+
mMapView = mapView
1179+
11461180

1147-
val matchParent = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
1148-
mapView.setLayoutParams(matchParent)
1149-
addView(mapView)
1181+
val matchParent = FrameLayout.LayoutParams(
1182+
ViewGroup.LayoutParams.MATCH_PARENT,
1183+
ViewGroup.LayoutParams.MATCH_PARENT
1184+
)
1185+
mapView.setLayoutParams(matchParent)
1186+
addView(mapView)
1187+
}
11501188
this.addOnLayoutChangeListener(this)
11511189

11521190
val map = mapView.getMapboxMap()

android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ open class RNMBXMapViewManager(context: ReactApplicationContext, val viewTagReso
337337
}
338338
}
339339

340+
@ReactProp(name = "mapViewImpl")
341+
override fun setMapViewImpl(mapView: RNMBXMapView, value: Dynamic?) {
342+
value?.let {
343+
mapView.mapViewImpl = it.asString()
344+
}
345+
}
346+
340347
override fun setCompassImage(view: RNMBXMapView, value: Dynamic?) {
341348
// TODO: No-op on Android?
342349
}

android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ public void setProperty(T view, String propName, @Nullable Object value) {
100100
case "compassImage":
101101
mViewManager.setCompassImage(view, new DynamicFromObject(value));
102102
break;
103+
case "mapViewImpl":
104+
mViewManager.setMapViewImpl(view, new DynamicFromObject(value));
105+
break;
103106
default:
104107
super.setProperty(view, propName, value);
105108
}

android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerInterface.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ public interface RNMBXMapViewManagerInterface<T extends View> {
3939
void setAttributionViewMargins(T view, Dynamic value);
4040
void setAttributionViewPosition(T view, Dynamic value);
4141
void setCompassImage(T view, Dynamic value);
42+
void setMapViewImpl(T view, Dynamic value);
4243
}

ios/RNMBX/RNMBXMapView.swift

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@
22
import Turf
33
import MapKit
44

5+
public typealias RNMBXMapViewFactoryFunc = (String, UIView) -> MapView?;
6+
7+
/**
8+
* Experimental MapView factory for advanced usecases
9+
*/
10+
public class RNMBXMapViewFactory {
11+
private static var factories: [String: RNMBXMapViewFactoryFunc] = [:];
12+
13+
static func get(_ id: String) -> RNMBXMapViewFactoryFunc? {
14+
if let id = id.split(separator: ":", maxSplits: 1).first {
15+
return factories[String(id)]
16+
}
17+
return nil
18+
}
19+
20+
public static func register(_ id: String, factory: @escaping RNMBXMapViewFactoryFunc) {
21+
factories.updateValue(factory, forKey: id)
22+
}
23+
}
24+
525
class FeatureEntry {
626
let feature: RNMBXMapComponent
727
let view: UIView
@@ -132,6 +152,9 @@ open class RNMBXMapView: UIView {
132152

133153
@objc
134154
public var deselectAnnotationOnTap: Bool = false
155+
156+
@objc
157+
public var mapViewImpl : String? = nil
135158

136159
#if RNMBX_11
137160
var cancelables = Set<AnyCancelable>()
@@ -149,19 +172,32 @@ open class RNMBXMapView: UIView {
149172

150173
var _mapView: MapView! = nil
151174
func createMapView() {
152-
#if RNMBX_11
153-
_mapView = MapView(frame: self.bounds, mapInitOptions: MapInitOptions())
154-
#else
155-
let resourceOptions = ResourceOptions(accessToken: RNMBXModule.accessToken!)
156-
_mapView = MapView(frame: frame, mapInitOptions: MapInitOptions(resourceOptions: resourceOptions))
157-
#endif
158-
_mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
159-
addSubview(_mapView)
175+
if let mapViewImpl = mapViewImpl, let mapViewInstance = createAndAddMapViewImpl(mapViewImpl, self) {
176+
_mapView = mapViewInstance
177+
} else {
178+
#if RNMBX_11
179+
_mapView = MapView(frame: self.bounds, mapInitOptions: MapInitOptions())
180+
#else
181+
let resourceOptions = ResourceOptions(accessToken: RNMBXModule.accessToken!)
182+
_mapView = MapView(frame: frame, mapInitOptions: MapInitOptions(resourceOptions: resourceOptions))
183+
#endif
184+
_mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
185+
addSubview(_mapView)
186+
}
160187

161188
_mapView.gestures.delegate = self
162189
setupEvents()
163190
}
164-
191+
192+
func createAndAddMapViewImpl(_ impl: String, _ view: RNMBXMapView) -> MapView? {
193+
if let factory = RNMBXMapViewFactory.get(impl) {
194+
return factory(impl, view) as? MapView;
195+
} else {
196+
Logger.log(level:.error, message: "No mapview factory registered for: \(impl)")
197+
return nil
198+
}
199+
}
200+
165201
var mapView : MapView! {
166202
get { return _mapView }
167203
}

scripts/autogenHelpers/DocJSONBuilder.mjs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,18 @@ class DocJSONBuilder {
5555
}
5656

5757
postprocess(component, name) {
58-
// Remove all private methods and parse examples from docblock
58+
// Remove all private methods, and properties and parse examples from docblock
5959

6060
if (!Array.isArray(component.methods)) {
6161
return;
6262
}
6363

64+
for (const [propName, prop] of Object.entries(component.props)) {
65+
if (prop.description.includes('@private')) {
66+
delete component.props[propName];
67+
}
68+
}
69+
6470
component.name = name;
6571

6672
// Main description

src/components/MapView.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,11 @@ type Props = ViewProps & {
433433
* the onPress event for the taps that deselect the annotation. Default is false.
434434
*/
435435
deselectAnnotationOnTap?: boolean;
436+
437+
/**
438+
* @private Experimental support for custom MapView instances
439+
*/
440+
mapViewImpl?: string;
436441
};
437442

438443
type CallbablePropKeys =

src/specs/RNMBXMapViewNativeComponent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export interface NativeProps extends ViewProps {
7676
onLongPress?: DirectEventHandler<OnPressEventType>;
7777
onMapChange?: DirectEventHandler<OnMapChangeEventType>;
7878
onCameraChanged?: DirectEventHandler<OnCameraChangedEventType>;
79+
80+
mapViewImpl?: OptionalProp<string>;
7981
}
8082

8183
export default codegenNativeComponent<NativeProps>(

0 commit comments

Comments
 (0)