expo-gaode-map 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +81 -7
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +6 -0
- package/ios/ExpoGaodeMapView.swift +66 -11
- package/ios/overlays/MarkerView.swift +140 -55
- package/package.json +1 -1
- package/test/ClockMapView.tsx +504 -0
- package/test/useMap.ts +1348 -0
|
@@ -27,6 +27,18 @@ import expo.modules.gaodemap.overlays.*
|
|
|
27
27
|
@Suppress("ViewConstructor")
|
|
28
28
|
class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* 拦截 React Native 的 ViewManager 操作
|
|
32
|
+
* 重写 requestLayout 防止在移除视图时触发布局异常
|
|
33
|
+
*/
|
|
34
|
+
override fun requestLayout() {
|
|
35
|
+
try {
|
|
36
|
+
super.requestLayout()
|
|
37
|
+
} catch (e: Exception) {
|
|
38
|
+
Log.e(TAG, "requestLayout 异常被捕获", e)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
companion object {
|
|
31
43
|
private const val TAG = "ExpoGaodeMapView"
|
|
32
44
|
}
|
|
@@ -504,12 +516,23 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
504
516
|
|
|
505
517
|
/**
|
|
506
518
|
* 添加子视图时自动连接到地图
|
|
519
|
+
*
|
|
520
|
+
* 关键修复:MarkerView 不进入视图层级,但要确保 React Native 追踪正确
|
|
507
521
|
*/
|
|
508
522
|
override fun addView(child: View?, index: Int) {
|
|
509
523
|
if (child is MarkerView) {
|
|
510
|
-
//
|
|
524
|
+
// ✅ MarkerView 不加入视图层级
|
|
511
525
|
child.setMap(aMap)
|
|
512
526
|
markerViews.add(child)
|
|
527
|
+
Log.d(TAG, "✅ MarkerView 已添加到特殊列表(不在视图层级中),数量: ${markerViews.size}")
|
|
528
|
+
// ⚠️ 不调用 super.addView,所以 React Native 不会追踪它
|
|
529
|
+
return
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ⚠️ 如果是 MapView 本身,必须添加
|
|
533
|
+
if (child is com.amap.api.maps.MapView) {
|
|
534
|
+
super.addView(child, index)
|
|
535
|
+
Log.d(TAG, "✅ MapView 已添加")
|
|
513
536
|
return
|
|
514
537
|
}
|
|
515
538
|
|
|
@@ -533,22 +556,73 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
533
556
|
*/
|
|
534
557
|
override fun removeView(child: View?) {
|
|
535
558
|
if (child is MarkerView) {
|
|
536
|
-
// 从 MarkerView
|
|
559
|
+
// 从 MarkerView 列表中移除并清理
|
|
537
560
|
markerViews.remove(child)
|
|
561
|
+
child.removeMarker()
|
|
562
|
+
Log.d(TAG, "✅ MarkerView 已清理,当前 markerViews 数量: ${markerViews.size}")
|
|
538
563
|
return
|
|
539
564
|
}
|
|
540
|
-
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
super.removeView(child)
|
|
568
|
+
} catch (e: Exception) {
|
|
569
|
+
Log.e(TAG, "removeView 异常", e)
|
|
570
|
+
}
|
|
541
571
|
}
|
|
542
572
|
|
|
543
573
|
/**
|
|
544
574
|
* 按索引移除视图
|
|
575
|
+
*
|
|
576
|
+
* 终极修复:完全忽略所有无效的移除请求
|
|
545
577
|
*/
|
|
546
578
|
override fun removeViewAt(index: Int) {
|
|
547
|
-
|
|
548
|
-
|
|
579
|
+
try {
|
|
580
|
+
val actualChildCount = super.getChildCount()
|
|
581
|
+
|
|
582
|
+
Log.d(TAG, "removeViewAt 调用: index=$index, super.childCount=$actualChildCount")
|
|
583
|
+
|
|
584
|
+
// ✅ 如果没有子视图,直接返回
|
|
585
|
+
if (actualChildCount == 0) {
|
|
586
|
+
Log.w(TAG, "⚠️ 无子视图,忽略: index=$index")
|
|
587
|
+
return
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// ✅ 索引越界,直接返回
|
|
591
|
+
if (index < 0 || index >= actualChildCount) {
|
|
592
|
+
Log.w(TAG, "⚠️ 索引越界,忽略: index=$index, childCount=$actualChildCount")
|
|
593
|
+
return
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// 检查要移除的视图类型
|
|
597
|
+
val child = super.getChildAt(index)
|
|
598
|
+
|
|
599
|
+
// ❌ MapView 绝对不能移除
|
|
600
|
+
if (child is com.amap.api.maps.MapView) {
|
|
601
|
+
Log.e(TAG, "❌ 阻止移除 MapView!index=$index")
|
|
602
|
+
// 不移除,直接返回
|
|
603
|
+
return
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// MarkerView 特殊处理(虽然理论上不应该出现在这里)
|
|
607
|
+
if (child is MarkerView) {
|
|
608
|
+
Log.d(TAG, "⚠️ 发现 MarkerView 在视图层级中,使用 removeView")
|
|
609
|
+
removeView(child)
|
|
610
|
+
return
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// 正常移除其他视图
|
|
549
614
|
super.removeViewAt(index)
|
|
550
|
-
|
|
551
|
-
|
|
615
|
+
Log.d(TAG, "✅ 成功移除视图: index=$index")
|
|
616
|
+
|
|
617
|
+
} catch (e: IllegalArgumentException) {
|
|
618
|
+
// 索引异常,静默忽略
|
|
619
|
+
Log.w(TAG, "⚠️ 索引异常,已忽略: ${e.message}")
|
|
620
|
+
} catch (e: IndexOutOfBoundsException) {
|
|
621
|
+
// 越界异常,静默忽略
|
|
622
|
+
Log.w(TAG, "⚠️ 越界异常,已忽略: ${e.message}")
|
|
623
|
+
} catch (e: Exception) {
|
|
624
|
+
// 其他所有异常,静默忽略
|
|
625
|
+
Log.e(TAG, "⚠️ 移除视图异常,已忽略", e)
|
|
552
626
|
}
|
|
553
627
|
}
|
|
554
628
|
|
|
@@ -12,6 +12,12 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
12
12
|
|
|
13
13
|
View(ExpoGaodeMapView::class) {
|
|
14
14
|
Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress", "onPolygonPress", "onPolylinePress")
|
|
15
|
+
|
|
16
|
+
// ✅ 关键修复:拦截 React Native 的视图操作异常
|
|
17
|
+
OnViewDestroys { view: ExpoGaodeMapView ->
|
|
18
|
+
// 在视图销毁时不做任何抛出异常的操作
|
|
19
|
+
android.util.Log.d("ExpoGaodeMapViewModule", "视图正在销毁,清理资源")
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
Prop<Int>("mapType") { view, type ->
|
|
17
23
|
view.mapType = type
|
|
@@ -88,15 +88,35 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
88
88
|
required init(appContext: AppContext? = nil) {
|
|
89
89
|
super.init(appContext: appContext)
|
|
90
90
|
|
|
91
|
+
print("🗺️ [MapView Init] 开始初始化地图视图")
|
|
92
|
+
print("🗺️ [MapView Init] bounds: \(bounds)")
|
|
93
|
+
|
|
91
94
|
// 确保隐私合规已设置
|
|
92
95
|
MAMapView.updatePrivacyAgree(.didAgree)
|
|
93
96
|
MAMapView.updatePrivacyShow(.didShow, privacyInfo: .didContain)
|
|
97
|
+
print("🗺️ [MapView Init] 隐私合规设置完成")
|
|
94
98
|
|
|
99
|
+
// 创建 MAMapView(注意:如果 API Key 未设置,可能会在后续操作时报错)
|
|
95
100
|
mapView = MAMapView(frame: bounds)
|
|
101
|
+
|
|
102
|
+
// 检查是否创建成功
|
|
103
|
+
if mapView == nil {
|
|
104
|
+
print("❌ [MapView Init] MAMapView 创建失败!请检查:")
|
|
105
|
+
print("❌ [MapView Init] 1. iOS API Key 是否已正确配置")
|
|
106
|
+
print("❌ [MapView Init] 2. 是否调用了 initSDK({ iosKey: 'your_key' })")
|
|
107
|
+
print("❌ [MapView Init] 3. API Key 是否有效")
|
|
108
|
+
} else {
|
|
109
|
+
print("🗺️ [MapView Init] ✅ MAMapView 创建成功, frame: \(mapView.frame)")
|
|
110
|
+
}
|
|
111
|
+
|
|
96
112
|
mapView.delegate = self
|
|
97
113
|
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
98
114
|
|
|
99
|
-
//
|
|
115
|
+
// 立即添加 mapView 到视图层级,确保地图可见
|
|
116
|
+
addSubview(mapView)
|
|
117
|
+
print("🗺️ [MapView Init] ✅ mapView 已添加到视图层级")
|
|
118
|
+
print("🗺️ [MapView Init] mapView.superview: \(mapView.superview != nil ? "存在" : "nil")")
|
|
119
|
+
print("🗺️ [MapView Init] subviews.count: \(subviews.count)")
|
|
100
120
|
|
|
101
121
|
cameraManager = CameraManager(mapView: mapView)
|
|
102
122
|
uiManager = UIManager(mapView: mapView)
|
|
@@ -125,11 +145,17 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
setupDefaultConfig()
|
|
148
|
+
print("🗺️ [MapView Init] 初始化完成")
|
|
128
149
|
}
|
|
129
150
|
|
|
130
151
|
override func layoutSubviews() {
|
|
131
152
|
super.layoutSubviews()
|
|
153
|
+
print("🗺️ [MapView Layout] layoutSubviews 被调用")
|
|
154
|
+
print("🗺️ [MapView Layout] 旧 frame: \(mapView.frame), 新 bounds: \(bounds)")
|
|
132
155
|
mapView.frame = bounds
|
|
156
|
+
print("🗺️ [MapView Layout] mapView frame 已更新: \(mapView.frame)")
|
|
157
|
+
print("🗺️ [MapView Layout] mapView.superview: \(mapView.superview != nil ? "存在" : "nil")")
|
|
158
|
+
print("🗺️ [MapView Layout] subviews.count: \(subviews.count)")
|
|
133
159
|
|
|
134
160
|
// 收集并设置 MarkerView
|
|
135
161
|
collectAndSetupMarkerViews()
|
|
@@ -151,14 +177,16 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
151
177
|
* 将地图实例传递给覆盖物子视图
|
|
152
178
|
*/
|
|
153
179
|
override func addSubview(_ view: UIView) {
|
|
180
|
+
super.addSubview(view)
|
|
181
|
+
|
|
154
182
|
if let markerView = view as? MarkerView {
|
|
155
|
-
//
|
|
183
|
+
// MarkerView 需要添加到视图层级以便其 children 可以渲染
|
|
184
|
+
// 但将其移到屏幕外,使其不可见
|
|
185
|
+
markerView.frame = CGRect(x: -10000, y: -10000, width: 1, height: 1)
|
|
156
186
|
markerView.setMap(mapView)
|
|
157
187
|
return
|
|
158
188
|
}
|
|
159
189
|
|
|
160
|
-
super.addSubview(view)
|
|
161
|
-
|
|
162
190
|
if let circleView = view as? CircleView {
|
|
163
191
|
circleView.setMap(mapView)
|
|
164
192
|
} else if let polylineView = view as? PolylineView {
|
|
@@ -193,15 +221,17 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
193
221
|
* 在 Props 更新时调用
|
|
194
222
|
*/
|
|
195
223
|
func applyProps() {
|
|
224
|
+
print("🗺️ [MapView Props] applyProps 被调用")
|
|
225
|
+
print("🗺️ [MapView Props] mapView.superview: \(mapView.superview != nil ? "存在" : "nil")")
|
|
226
|
+
print("🗺️ [MapView Props] mapView.frame: \(mapView.frame)")
|
|
227
|
+
print("🗺️ [MapView Props] initialCameraPosition: \(initialCameraPosition != nil ? "存在" : "nil")")
|
|
228
|
+
|
|
196
229
|
uiManager.setMapType(mapType)
|
|
197
230
|
|
|
198
|
-
//
|
|
199
|
-
if let position = initialCameraPosition
|
|
231
|
+
// 如果有初始位置,设置相机位置
|
|
232
|
+
if let position = initialCameraPosition {
|
|
233
|
+
print("🗺️ [MapView Props] 设置初始相机位置: \(position)")
|
|
200
234
|
cameraManager.setInitialCameraPosition(position)
|
|
201
|
-
addSubview(mapView)
|
|
202
|
-
} else if mapView.superview == nil {
|
|
203
|
-
// 没有初始位置,直接添加地图
|
|
204
|
-
addSubview(mapView)
|
|
205
235
|
}
|
|
206
236
|
|
|
207
237
|
uiManager.setShowsScale(showsScale)
|
|
@@ -217,6 +247,10 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
217
247
|
|
|
218
248
|
// 收集并设置所有 MarkerView
|
|
219
249
|
collectAndSetupMarkerViews()
|
|
250
|
+
|
|
251
|
+
print("🗺️ [MapView Props] Props 应用完成")
|
|
252
|
+
print("🗺️ [MapView Props] 最终 mapView.superview: \(mapView.superview != nil ? "存在" : "nil")")
|
|
253
|
+
print("🗺️ [MapView Props] 最终 subviews.count: \(subviews.count)")
|
|
220
254
|
}
|
|
221
255
|
|
|
222
256
|
// MARK: - 缩放控制
|
|
@@ -350,8 +384,16 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate {
|
|
|
350
384
|
* 析构函数 - 清理资源
|
|
351
385
|
*/
|
|
352
386
|
deinit {
|
|
387
|
+
print("🗺️ [MapView] deinit 开始清理")
|
|
388
|
+
|
|
389
|
+
// 先设置 delegate 为 nil,停止接收回调
|
|
353
390
|
mapView?.delegate = nil
|
|
354
|
-
|
|
391
|
+
|
|
392
|
+
// 不调用 overlayManager.clear()
|
|
393
|
+
// 因为声明式的 Marker/Circle 等会在自己的 willMove(toSuperview:) 中清理
|
|
394
|
+
// 调用 clear() 可能导致重复移除和崩溃
|
|
395
|
+
|
|
396
|
+
print("🗺️ [MapView] deinit 完成")
|
|
355
397
|
}
|
|
356
398
|
}
|
|
357
399
|
|
|
@@ -364,6 +406,9 @@ extension ExpoGaodeMapView {
|
|
|
364
406
|
public func mapViewDidFinishLoadingMap(_ mapView: MAMapView) {
|
|
365
407
|
guard !isMapLoaded else { return }
|
|
366
408
|
isMapLoaded = true
|
|
409
|
+
print("🗺️ [MapView Delegate] ✅ 地图加载完成")
|
|
410
|
+
print("🗺️ [MapView Delegate] mapView.frame: \(mapView.frame)")
|
|
411
|
+
print("🗺️ [MapView Delegate] mapView.superview: \(mapView.superview != nil ? "存在" : "nil")")
|
|
367
412
|
onLoad(["loaded": true])
|
|
368
413
|
}
|
|
369
414
|
|
|
@@ -585,7 +630,17 @@ extension ExpoGaodeMapView {
|
|
|
585
630
|
}
|
|
586
631
|
|
|
587
632
|
if annotation.isKind(of: MAPointAnnotation.self) {
|
|
633
|
+
// 首先检查是否是声明式 MarkerView 的 annotation
|
|
634
|
+
for subview in subviews {
|
|
635
|
+
if let markerView = subview as? MarkerView, markerView.annotation === annotation {
|
|
636
|
+
print("🎯 [MapView Delegate] 找到声明式 MarkerView,调用其 getAnnotationView")
|
|
637
|
+
return markerView.getAnnotationView(for: mapView, annotation: annotation)
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// 如果不是声明式的,检查是否是命令式 API 的 Marker
|
|
588
642
|
guard let props = overlayManager.getMarkerProps(for: annotation) else {
|
|
643
|
+
print("⚠️ [MapView Delegate] 未找到对应的 Marker props")
|
|
589
644
|
return nil
|
|
590
645
|
}
|
|
591
646
|
|
|
@@ -48,14 +48,18 @@ class MarkerView: ExpoView {
|
|
|
48
48
|
var pinColor: String = "red"
|
|
49
49
|
/// 是否显示气泡
|
|
50
50
|
var canShowCallout: Bool = true
|
|
51
|
-
///
|
|
52
|
-
private var mapView: MAMapView?
|
|
51
|
+
/// 地图视图弱引用(避免循环引用)
|
|
52
|
+
private weak var mapView: MAMapView?
|
|
53
53
|
/// 标记点对象
|
|
54
54
|
var annotation: MAPointAnnotation?
|
|
55
|
+
/// 标记是否正在被移除(防止重复移除)
|
|
56
|
+
private var isRemoving: Bool = false
|
|
55
57
|
/// 标记点视图
|
|
56
58
|
private var annotationView: MAAnnotationView?
|
|
57
59
|
/// 待处理的位置(在 setMap 之前设置)
|
|
58
60
|
private var pendingPosition: [String: Double]?
|
|
61
|
+
/// 延迟添加任务
|
|
62
|
+
private var pendingAddTask: DispatchWorkItem?
|
|
59
63
|
|
|
60
64
|
required init(appContext: AppContext? = nil) {
|
|
61
65
|
super.init(appContext: appContext)
|
|
@@ -86,12 +90,20 @@ class MarkerView: ExpoView {
|
|
|
86
90
|
guard let mapView = mapView,
|
|
87
91
|
let latitude = position["latitude"],
|
|
88
92
|
let longitude = position["longitude"] else {
|
|
93
|
+
print("⚠️ [MarkerView] updateAnnotation: mapView 或坐标为 nil")
|
|
89
94
|
return
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
|
|
97
|
+
print("📍 [MarkerView] updateAnnotation: 位置 (\(latitude), \(longitude)), subviews: \(self.subviews.count)")
|
|
98
|
+
|
|
99
|
+
// 取消之前的延迟任务
|
|
100
|
+
pendingAddTask?.cancel()
|
|
101
|
+
|
|
102
|
+
// 移除旧的标记(在主线程执行)
|
|
93
103
|
if let oldAnnotation = annotation {
|
|
94
|
-
|
|
104
|
+
DispatchQueue.main.async {
|
|
105
|
+
mapView.removeAnnotation(oldAnnotation)
|
|
106
|
+
}
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
// 创建新的标记
|
|
@@ -100,51 +112,59 @@ class MarkerView: ExpoView {
|
|
|
100
112
|
annotation.title = title
|
|
101
113
|
annotation.subtitle = markerDescription
|
|
102
114
|
|
|
103
|
-
mapView.addAnnotation(annotation)
|
|
104
115
|
self.annotation = annotation
|
|
105
116
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
guard let self = self else {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
guard let self = self else { return }
|
|
115
|
-
self.updateMarkerImage()
|
|
117
|
+
// 延迟添加到地图,等待 React Native 渲染 children
|
|
118
|
+
let task = DispatchWorkItem { [weak self] in
|
|
119
|
+
guard let self = self, !self.isRemoving else {
|
|
120
|
+
print("⚠️ [MarkerView] 延迟任务取消,isRemoving: \(self?.isRemoving ?? true)")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
print("✅ [MarkerView] Annotation 延迟添加,当前 subviews: \(self.subviews.count)")
|
|
124
|
+
mapView.addAnnotation(annotation)
|
|
116
125
|
}
|
|
126
|
+
pendingAddTask = task
|
|
127
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: task)
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
/**
|
|
120
|
-
*
|
|
131
|
+
* 获取 annotation 视图(由 ExpoGaodeMapView 调用)
|
|
121
132
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
func getAnnotationView(for mapView: MAMapView, annotation: MAAnnotation) -> MAAnnotationView? {
|
|
134
|
+
print("🎨 [MarkerView] getAnnotationView 被调用")
|
|
135
|
+
print("🎨 [MarkerView] subviews.count: \(self.subviews.count)")
|
|
136
|
+
|
|
137
|
+
let reuseId = "custom_marker_\(ObjectIdentifier(self).hashValue)"
|
|
138
|
+
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
|
|
139
|
+
|
|
140
|
+
if annotationView == nil {
|
|
141
|
+
annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
|
|
142
|
+
annotationView?.canShowCallout = canShowCallout
|
|
143
|
+
annotationView?.isDraggable = draggable
|
|
128
144
|
}
|
|
129
145
|
|
|
130
|
-
|
|
146
|
+
annotationView?.annotation = annotation
|
|
147
|
+
self.annotationView = annotationView
|
|
131
148
|
|
|
149
|
+
// 设置图标
|
|
132
150
|
if self.subviews.count > 0 {
|
|
133
|
-
|
|
151
|
+
print("🎨 [MarkerView] 尝试创建自定义图片...")
|
|
134
152
|
if let image = self.createImageFromSubviews() {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
print("✅ [MarkerView] 自定义图片创建成功, size: \(image.size)")
|
|
154
|
+
annotationView?.image = image
|
|
155
|
+
annotationView?.centerOffset = CGPoint(x: 0, y: -image.size.height / 2)
|
|
138
156
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
157
|
+
print("❌ [MarkerView] 自定义图片创建失败,使用默认图标")
|
|
158
|
+
annotationView?.image = self.createDefaultMarkerImage()
|
|
159
|
+
annotationView?.centerOffset = CGPoint(x: 0, y: -18)
|
|
142
160
|
}
|
|
143
161
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
162
|
+
print("📍 [MarkerView] 没有子视图,使用默认图标")
|
|
163
|
+
annotationView?.image = self.createDefaultMarkerImage()
|
|
164
|
+
annotationView?.centerOffset = CGPoint(x: 0, y: -18)
|
|
147
165
|
}
|
|
166
|
+
|
|
167
|
+
return annotationView
|
|
148
168
|
}
|
|
149
169
|
|
|
150
170
|
/**
|
|
@@ -270,22 +290,75 @@ class MarkerView: ExpoView {
|
|
|
270
290
|
return UIGraphicsGetImageFromCurrentImageContext()
|
|
271
291
|
}
|
|
272
292
|
|
|
293
|
+
/**
|
|
294
|
+
* 当视图即将从父视图移除时调用
|
|
295
|
+
*/
|
|
296
|
+
override func willMove(toSuperview newSuperview: UIView?) {
|
|
297
|
+
super.willMove(toSuperview: newSuperview)
|
|
298
|
+
|
|
299
|
+
// 如果 newSuperview 为 nil,说明视图正在被移除
|
|
300
|
+
if newSuperview == nil {
|
|
301
|
+
removeAnnotationFromMap()
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 从地图移除标记点
|
|
307
|
+
*/
|
|
308
|
+
private func removeAnnotationFromMap() {
|
|
309
|
+
guard !isRemoving else { return }
|
|
310
|
+
isRemoving = true
|
|
311
|
+
|
|
312
|
+
print("🗑️ [MarkerView] removeAnnotationFromMap 被调用")
|
|
313
|
+
|
|
314
|
+
// 取消任何待处理的延迟任务
|
|
315
|
+
pendingAddTask?.cancel()
|
|
316
|
+
pendingAddTask = nil
|
|
317
|
+
|
|
318
|
+
// 立即保存引用并清空属性,避免在异步块中访问 self
|
|
319
|
+
guard let mapView = mapView, let annotation = annotation else {
|
|
320
|
+
print("⚠️ [MarkerView] 没有 annotation 需要移除")
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
self.annotation = nil
|
|
324
|
+
self.annotationView = nil
|
|
325
|
+
|
|
326
|
+
// 同步移除,避免对象在异步块执行时已被释放
|
|
327
|
+
if Thread.isMainThread {
|
|
328
|
+
mapView.removeAnnotation(annotation)
|
|
329
|
+
print("✅ [MarkerView] Annotation 已从地图移除(主线程)")
|
|
330
|
+
} else {
|
|
331
|
+
DispatchQueue.main.sync {
|
|
332
|
+
mapView.removeAnnotation(annotation)
|
|
333
|
+
print("✅ [MarkerView] Annotation 已从地图移除(同步到主线程)")
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
273
338
|
override func willRemoveSubview(_ subview: UIView) {
|
|
274
339
|
super.willRemoveSubview(subview)
|
|
275
340
|
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
341
|
+
// 如果正在移除,不要执行任何操作
|
|
342
|
+
guard !isRemoving else {
|
|
343
|
+
print("⚠️ [MarkerView] willRemoveSubview 被调用但正在移除,忽略")
|
|
344
|
+
return
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
print("🎨 [MarkerView] willRemoveSubview 被调用,剩余 subviews.count: \(self.subviews.count - 1)")
|
|
348
|
+
|
|
349
|
+
// 子视图移除后,需要刷新 annotation 视图
|
|
350
|
+
if self.subviews.count <= 1 {
|
|
351
|
+
// 所有子视图已移除,刷新以恢复默认图标
|
|
352
|
+
if let mapView = mapView, let annotation = annotation {
|
|
353
|
+
DispatchQueue.main.async { [weak self] in
|
|
354
|
+
guard let self = self, !self.isRemoving else {
|
|
355
|
+
print("⚠️ [MarkerView] 异步刷新时已被移除,取消操作")
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
mapView.removeAnnotation(annotation)
|
|
359
|
+
mapView.addAnnotation(annotation)
|
|
360
|
+
print("✅ [MarkerView] Annotation 已刷新为默认图标")
|
|
285
361
|
}
|
|
286
|
-
} else {
|
|
287
|
-
// 还有子视图,更新图标
|
|
288
|
-
self.updateMarkerImage()
|
|
289
362
|
}
|
|
290
363
|
}
|
|
291
364
|
}
|
|
@@ -293,14 +366,26 @@ class MarkerView: ExpoView {
|
|
|
293
366
|
override func didAddSubview(_ subview: UIView) {
|
|
294
367
|
super.didAddSubview(subview)
|
|
295
368
|
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
369
|
+
// 如果正在移除,不要执行任何操作
|
|
370
|
+
guard !isRemoving else {
|
|
371
|
+
print("⚠️ [MarkerView] didAddSubview 被调用但正在移除,忽略")
|
|
372
|
+
return
|
|
299
373
|
}
|
|
300
374
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
375
|
+
print("🎨 [MarkerView] didAddSubview 被调用,subviews.count: \(self.subviews.count)")
|
|
376
|
+
|
|
377
|
+
// 子视图添加后,需要刷新 annotation 视图
|
|
378
|
+
// 通过移除并重新添加 annotation 来触发 getAnnotationView 调用
|
|
379
|
+
if let mapView = mapView, let annotation = annotation {
|
|
380
|
+
DispatchQueue.main.async { [weak self] in
|
|
381
|
+
guard let self = self, !self.isRemoving else {
|
|
382
|
+
print("⚠️ [MarkerView] 异步刷新时已被移除,取消操作")
|
|
383
|
+
return
|
|
384
|
+
}
|
|
385
|
+
mapView.removeAnnotation(annotation)
|
|
386
|
+
mapView.addAnnotation(annotation)
|
|
387
|
+
print("✅ [MarkerView] Annotation 已刷新")
|
|
388
|
+
}
|
|
304
389
|
}
|
|
305
390
|
}
|
|
306
391
|
|
|
@@ -415,11 +500,11 @@ class MarkerView: ExpoView {
|
|
|
415
500
|
}
|
|
416
501
|
|
|
417
502
|
/**
|
|
418
|
-
*
|
|
503
|
+
* 析构函数 - 不执行任何清理
|
|
504
|
+
* 清理工作已在 willMove(toSuperview:) 中完成
|
|
419
505
|
*/
|
|
420
506
|
deinit {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
507
|
+
// 不执行任何操作,避免访问已释放的对象
|
|
508
|
+
// 所有清理都应该在 willMove(toSuperview:) 中完成
|
|
424
509
|
}
|
|
425
510
|
}
|