Skip to content

Commit 6ce02de

Browse files
authored
fix(point annotation): selected property should select/deselect (#4165)
* fix(point annotation): selected property should select/deselect a point annotation Co-Authored-By: Miklós Fazekas <mfazekas@szemafor.com> * fix(android): use non-nullable Dynamic and log null selected values * fix(ios): fix callout not rendering on PointAnnotation selection Callout children were mounted into the ComponentView instead of the contentView (RNMBXCallout), producing a transparent snapshot. Override mountChildComponentView in RNMBXCalloutComponentView to insert children into the contentView. Also set iconAllowOverlap on the callout annotation manager so callouts are not hidden by symbol collision. * fix(android): add setReactSelected and mIsSelected tracking to RNMBXPointAnnotation
1 parent 963ee23 commit 6ce02de

File tree

7 files changed

+80
-5
lines changed

7 files changed

+80
-5
lines changed

android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotation.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
3636
private val mTitle: String? = null
3737
private val mSnippet: String? = null
3838
private var mAnchor: Array<Float>? = null
39-
private val mIsSelected = false
39+
private var mIsSelected = false
4040
private var mDraggable = false
4141
private var mChildView: View? = null
4242
private var mChildBitmap: Bitmap? = null
@@ -187,7 +187,19 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
187187
}
188188
}
189189

190+
fun setReactSelected(selected: Boolean) {
191+
if (selected && !mIsSelected) {
192+
pointAnnotations?.let {
193+
it.deselectSelectedAnnotation()
194+
it.selectAnnotation(this)
195+
}
196+
} else if (!selected && mIsSelected) {
197+
pointAnnotations?.deselectAnnotation(this)
198+
}
199+
}
200+
190201
fun doSelect(shouldSendEvent: Boolean) {
202+
mIsSelected = true
191203
if (calloutView != null) {
192204
makeCallout()
193205
}
@@ -197,6 +209,7 @@ class RNMBXPointAnnotation(private val mContext: Context, private val mManager:
197209
}
198210

199211
fun doDeselect() {
212+
mIsSelected = false
200213
mManager.handleEvent(makeEvent(false))
201214
mCalloutSymbol?.let { mCalloutSymbol ->
202215
pointAnnotations?.delete(mCalloutSymbol)

android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ class RNMBXPointAnnotationManager(reactApplicationContext: ReactApplicationConte
7878
annotation.setAnchor(mapValue.getDouble("x").toFloat(), mapValue.getDouble("y").toFloat())
7979
}
8080

81+
override fun setSelected(
82+
annotation: RNMBXPointAnnotation,
83+
value: Dynamic
84+
) {
85+
if (value.isNull) {
86+
Logger.e("RNMBXPointAnnotationManager", "selected value is null")
87+
return
88+
}
89+
annotation.setReactSelected(value.asBoolean())
90+
}
91+
8192
@ReactProp(name = "draggable")
8293
override fun setDraggable(annotation: RNMBXPointAnnotation, draggable: Dynamic) {
8394
annotation.setDraggable(draggable.asBoolean())

ios/RNMBX/RNMBXCalloutComponentView.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ + (ComponentDescriptorProvider)componentDescriptorProvider
4545
return concreteComponentDescriptorProvider<RNMBXCalloutComponentDescriptor>();
4646
}
4747

48+
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
49+
{
50+
[_view insertSubview:childComponentView atIndex:index];
51+
}
52+
53+
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
54+
{
55+
[childComponentView removeFromSuperview];
56+
}
57+
4858
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
4959
{
5060
const auto &newProps = static_cast<const RNMBXCalloutProps &>(*props);

ios/RNMBX/RNMBXMapView.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ open class RNMBXMapView: UIView, RCTInvalidating {
236236
}()
237237

238238
lazy var calloutAnnotationManager : MapboxMaps.PointAnnotationManager = {
239-
return mapView.annotations.makePointAnnotationManager(id: "RNMBX-mapview-callouts")
239+
let manager = mapView.annotations.makePointAnnotationManager(id: "RNMBX-mapview-callouts")
240+
manager.iconAllowOverlap = true
241+
return manager
240242
}()
241243

242244
var _mapView: MapView! = nil
@@ -1893,6 +1895,20 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
18931895
// onTap(annotations: annotations)
18941896
}
18951897

1898+
func selected(pointAnnotation: RNMBXPointAnnotation) {
1899+
if (selected != nil) {
1900+
deselectCurrentlySelected(deselectAnnotationOnTap: false)
1901+
}
1902+
pointAnnotation.doSelect()
1903+
selected = pointAnnotation
1904+
}
1905+
1906+
func unselected(pointAnnotation: RNMBXPointAnnotation) {
1907+
if (selected == pointAnnotation) {
1908+
deselectCurrentlySelected(deselectAnnotationOnTap: false)
1909+
}
1910+
}
1911+
18961912
func deselectCurrentlySelected(deselectAnnotationOnTap: Bool = false) -> Bool {
18971913
if let selected = selected {
18981914
selected.doDeselect(deselectAnnotationOnMapTap: deselectAnnotationOnTap)
@@ -2120,6 +2136,7 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
21202136
)
21212137

21222138
func add(_ annotation: PointAnnotation, _ rnmbxPointAnnotation: RNMBXPointAnnotation) {
2139+
rnmbxPointAnnotation.manager = self
21232140
manager.annotations.append(annotation)
21242141
manager.refresh()
21252142
annotations.setObject(rnmbxPointAnnotation, forKey: annotation.id as NSString)

ios/RNMBX/RNMBXPointAnnotation.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ final class WeakRef<T: AnyObject> {
1010
}
1111
@objc
1212
public class RNMBXPointAnnotation : RNMBXInteractiveElement {
13+
weak var manager: RNMBXPointAnnotationManager? = nil
14+
1315
static let key = "RNMBXPointAnnotation"
1416
static var gid = 0;
1517

@@ -31,7 +33,25 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement {
3133
@objc public var onDrag: RCTBubblingEventBlock? = nil
3234
@objc public var onDragEnd: RCTBubblingEventBlock? = nil
3335
@objc public var onSelected: RCTBubblingEventBlock? = nil
34-
36+
37+
private var selected: Bool? = nil {
38+
didSet {
39+
update { annotation in
40+
if let selected = selected {
41+
annotation.isSelected = selected
42+
}
43+
}
44+
}
45+
}
46+
47+
@objc public func setReactSelected(_ _selected: Bool) {
48+
if (_selected == true && self.selected != true) {
49+
manager?.selected(pointAnnotation: self)
50+
} else if (_selected == false && self.selected == true) {
51+
manager?.unselected(pointAnnotation: self)
52+
}
53+
}
54+
3555
@objc public var coordinate : String? {
3656
didSet {
3757
_updateCoordinate()
@@ -173,14 +193,16 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement {
173193
}
174194

175195
func doSelect() {
196+
self.selected = true
176197
let event = makeEvent(isSelect: true)
177198
if let onSelected = onSelected {
178199
onSelected(event.toJSON())
179200
}
180201
onSelect()
181202
}
182-
203+
183204
func doDeselect(deselectAnnotationOnMapTap: Bool = false) {
205+
self.selected = false
184206
let event = makeEvent(isSelect: false, deselectAnnotationOnMapTap: deselectAnnotationOnMapTap)
185207
if let onDeselected = onDeselected {
186208
onDeselected(event.toJSON())
@@ -192,7 +214,7 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement {
192214
if let callout = callout,
193215
let calloutImage = _createViewSnapshot(view: callout),
194216
let point = point() {
195-
217+
196218
var calloutPtAnnotation = PointAnnotation(point: point)
197219
calloutId = calloutPtAnnotation.id
198220
let name = "rnviewcallout-\(gid())-\(calloutPtAnnotation.id)"

ios/RNMBX/RNMBXPointAnnotationComponentView.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
130130
RNMBX_OPTIONAL_PROP_BOOL(draggable)
131131
RNMBX_OPTIONAL_PROP_NSString(id)
132132
RNMBX_OPTIONAL_PROP_NSDictionary(anchor)
133+
RNMBX_REMAP_OPTIONAL_PROP_BOOL(selected, reactSelected)
133134

134135
[super updateProps:props oldProps:oldProps];
135136
}

src/specs/RNMBXPointAnnotationNativeComponent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface NativeProps extends ViewProps {
2828
draggable: UnsafeMixed<boolean>;
2929
id: UnsafeMixed<string>;
3030
anchor: UnsafeMixed<any>;
31+
selected: UnsafeMixed<boolean>;
3132

3233
onMapboxPointAnnotationDeselected: DirectEventHandler<OnMapboxPointAnnotationDeselectedEventType>;
3334
onMapboxPointAnnotationDrag: DirectEventHandler<OnMapboxPointAnnotationDragEventType>;

0 commit comments

Comments
 (0)