expo-gaode-map 1.1.5 → 1.1.7
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 +637 -627
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +0 -2
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +3 -15
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +5 -56
- package/android/src/main/java/expo/modules/gaodemap/modules/SDKInitializer.kt +0 -1
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +139 -175
- package/ios/ExpoGaodeMapModule.swift +0 -4
- package/ios/ExpoGaodeMapView.swift +24 -63
- package/ios/managers/OverlayManager.swift +0 -6
- package/ios/overlays/CircleView.swift +0 -3
- package/ios/overlays/ClusterViewModule.swift +0 -2
- package/ios/overlays/MarkerView.swift +21 -4
- package/ios/overlays/MultiPointViewModule.swift +0 -2
- package/ios/overlays/PolygonView.swift +2 -12
- package/ios/overlays/PolylineView.swift +2 -12
- package/ios/utils/PermissionManager.swift +0 -1
- package/package.json +1 -1
- package/test/ClockMapView.tsx +37 -9
- package/test/useMap.ts +35 -23
|
@@ -17,7 +17,7 @@ import expo.modules.gaodemap.overlays.*
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* 高德地图视图组件
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* 负责:
|
|
22
22
|
* - 地图视图的创建和管理
|
|
23
23
|
* - 地图事件的派发
|
|
@@ -26,643 +26,653 @@ import expo.modules.gaodemap.overlays.*
|
|
|
26
26
|
*/
|
|
27
27
|
@Suppress("ViewConstructor")
|
|
28
28
|
class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
+
|
|
42
|
+
companion object {
|
|
43
|
+
private const val TAG = "ExpoGaodeMapView"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Props 存储
|
|
47
|
+
/** 地图类型 */
|
|
48
|
+
internal var mapType: Int = 0
|
|
49
|
+
/** 初始相机位置 */
|
|
50
|
+
internal var initialCameraPosition: Map<String, Any?>? = null
|
|
51
|
+
/** 是否跟随用户位置 */
|
|
52
|
+
internal var followUserLocation: Boolean = false
|
|
53
|
+
|
|
54
|
+
/** 主线程 Handler */
|
|
55
|
+
private val mainHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
56
|
+
|
|
57
|
+
// 事件派发器
|
|
58
|
+
private val onMapPress by EventDispatcher()
|
|
59
|
+
private val onMapLongPress by EventDispatcher()
|
|
60
|
+
private val onLoad by EventDispatcher()
|
|
61
|
+
private val onLocation by EventDispatcher()
|
|
62
|
+
private val onMarkerPress by EventDispatcher()
|
|
63
|
+
private val onMarkerDragStart by EventDispatcher()
|
|
64
|
+
private val onMarkerDrag by EventDispatcher()
|
|
65
|
+
private val onMarkerDragEnd by EventDispatcher()
|
|
66
|
+
private val onCirclePress by EventDispatcher()
|
|
67
|
+
private val onPolygonPress by EventDispatcher()
|
|
68
|
+
private val onPolylinePress by EventDispatcher()
|
|
69
|
+
|
|
70
|
+
// 高德地图视图
|
|
71
|
+
private lateinit var mapView: MapView
|
|
72
|
+
private lateinit var aMap: AMap
|
|
73
|
+
|
|
74
|
+
// 管理器
|
|
75
|
+
private lateinit var cameraManager: CameraManager
|
|
76
|
+
private lateinit var uiManager: UIManager
|
|
77
|
+
private lateinit var overlayManager: OverlayManager
|
|
78
|
+
|
|
79
|
+
// 缓存初始相机位置,等待地图加载完成后设置
|
|
80
|
+
private var pendingCameraPosition: Map<String, Any?>? = null
|
|
81
|
+
private var isMapLoaded = false
|
|
82
|
+
|
|
83
|
+
init {
|
|
84
|
+
try {
|
|
85
|
+
// 确保隐私合规已设置
|
|
86
|
+
MapsInitializer.updatePrivacyShow(context, true, true)
|
|
87
|
+
MapsInitializer.updatePrivacyAgree(context, true)
|
|
88
|
+
|
|
89
|
+
// 创建地图视图
|
|
90
|
+
mapView = MapView(context)
|
|
91
|
+
mapView.onCreate(null)
|
|
92
|
+
aMap = mapView.map
|
|
93
|
+
|
|
94
|
+
// 初始化管理器
|
|
95
|
+
cameraManager = CameraManager(aMap)
|
|
96
|
+
uiManager = UIManager(aMap, context).apply {
|
|
97
|
+
// 设置定位变化回调
|
|
98
|
+
onLocationChanged = { latitude, longitude, accuracy ->
|
|
99
|
+
this@ExpoGaodeMapView.onLocation(mapOf(
|
|
100
|
+
"latitude" to latitude,
|
|
101
|
+
"longitude" to longitude,
|
|
102
|
+
"accuracy" to accuracy.toDouble(),
|
|
103
|
+
"timestamp" to System.currentTimeMillis()
|
|
104
|
+
))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
overlayManager = OverlayManager(aMap, context).apply {
|
|
108
|
+
onMarkerPress = { id, lat, lng ->
|
|
109
|
+
this@ExpoGaodeMapView.onMarkerPress(mapOf(
|
|
110
|
+
"markerId" to id,
|
|
111
|
+
"latitude" to lat,
|
|
112
|
+
"longitude" to lng
|
|
113
|
+
))
|
|
114
|
+
}
|
|
115
|
+
onMarkerDragStart = { id, lat, lng ->
|
|
116
|
+
this@ExpoGaodeMapView.onMarkerDragStart(mapOf(
|
|
117
|
+
"markerId" to id,
|
|
118
|
+
"latitude" to lat,
|
|
119
|
+
"longitude" to lng
|
|
120
|
+
))
|
|
121
|
+
}
|
|
122
|
+
onMarkerDrag = { id, lat, lng ->
|
|
123
|
+
this@ExpoGaodeMapView.onMarkerDrag(mapOf(
|
|
124
|
+
"markerId" to id,
|
|
125
|
+
"latitude" to lat,
|
|
126
|
+
"longitude" to lng
|
|
127
|
+
))
|
|
128
|
+
}
|
|
129
|
+
onMarkerDragEnd = { id, lat, lng ->
|
|
130
|
+
this@ExpoGaodeMapView.onMarkerDragEnd(mapOf(
|
|
131
|
+
"markerId" to id,
|
|
132
|
+
"latitude" to lat,
|
|
133
|
+
"longitude" to lng
|
|
134
|
+
))
|
|
135
|
+
}
|
|
136
|
+
onCirclePress = { id, lat, lng ->
|
|
137
|
+
this@ExpoGaodeMapView.onCirclePress(mapOf(
|
|
138
|
+
"circleId" to id,
|
|
139
|
+
"latitude" to lat,
|
|
140
|
+
"longitude" to lng
|
|
141
|
+
))
|
|
142
|
+
}
|
|
143
|
+
onPolygonPress = { id, lat, lng ->
|
|
144
|
+
this@ExpoGaodeMapView.onPolygonPress(mapOf(
|
|
145
|
+
"polygonId" to id,
|
|
146
|
+
"latitude" to lat,
|
|
147
|
+
"longitude" to lng
|
|
148
|
+
))
|
|
149
|
+
}
|
|
150
|
+
onPolylinePress = { id, lat, lng ->
|
|
151
|
+
this@ExpoGaodeMapView.onPolylinePress(mapOf(
|
|
152
|
+
"polylineId" to id,
|
|
153
|
+
"latitude" to lat,
|
|
154
|
+
"longitude" to lng
|
|
155
|
+
))
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 添加地图视图到布局
|
|
160
|
+
addView(mapView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
161
|
+
|
|
162
|
+
// 设置地图事件监听
|
|
163
|
+
setupMapListeners()
|
|
164
|
+
|
|
165
|
+
// 地图加载完成回调
|
|
166
|
+
aMap.setOnMapLoadedListener {
|
|
167
|
+
isMapLoaded = true
|
|
168
|
+
|
|
169
|
+
// 应用缓存的 Props
|
|
170
|
+
if (mapType != 0) {
|
|
171
|
+
setMapType(mapType)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
val positionToApply = initialCameraPosition ?: pendingCameraPosition
|
|
175
|
+
positionToApply?.let { position ->
|
|
176
|
+
applyInitialCameraPosition(position)
|
|
177
|
+
pendingCameraPosition = null
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onLoad(mapOf("loaded" to true))
|
|
181
|
+
}
|
|
182
|
+
} catch (e: Exception) {
|
|
183
|
+
Log.e(TAG, "ExpoGaodeMapView 初始化失败", e)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 设置地图事件监听
|
|
189
|
+
*/
|
|
190
|
+
private fun setupMapListeners() {
|
|
191
|
+
aMap.setOnMapClickListener { latLng ->
|
|
192
|
+
// 检查声明式 PolylineView
|
|
193
|
+
if (checkDeclarativePolylinePress(latLng)) {
|
|
194
|
+
return@setOnMapClickListener
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 检查声明式 PolygonView
|
|
198
|
+
if (checkDeclarativePolygonPress(latLng)) {
|
|
199
|
+
return@setOnMapClickListener
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 检查声明式 CircleView
|
|
203
|
+
if (checkDeclarativeCirclePress(latLng)) {
|
|
204
|
+
return@setOnMapClickListener
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 检查命令式圆形
|
|
208
|
+
val circleId = overlayManager.checkCirclePress(latLng)
|
|
209
|
+
if (circleId != null) {
|
|
210
|
+
overlayManager.onCirclePress?.invoke(circleId, latLng.latitude, latLng.longitude)
|
|
211
|
+
return@setOnMapClickListener
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 检查命令式多边形
|
|
215
|
+
val polygonId = overlayManager.checkPolygonPress(latLng)
|
|
216
|
+
if (polygonId != null) {
|
|
217
|
+
overlayManager.onPolygonPress?.invoke(polygonId, latLng.latitude, latLng.longitude)
|
|
218
|
+
return@setOnMapClickListener
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 检查命令式折线
|
|
222
|
+
val polylineId = overlayManager.checkPolylinePress(latLng)
|
|
223
|
+
if (polylineId != null) {
|
|
224
|
+
overlayManager.onPolylinePress?.invoke(polylineId, latLng.latitude, latLng.longitude)
|
|
225
|
+
return@setOnMapClickListener
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 如果都没点击,触发地图点击事件
|
|
229
|
+
onMapPress(mapOf(
|
|
230
|
+
"latitude" to latLng.latitude,
|
|
231
|
+
"longitude" to latLng.longitude
|
|
232
|
+
))
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
aMap.setOnMapLongClickListener { latLng ->
|
|
236
|
+
onMapLongPress(mapOf(
|
|
237
|
+
"latitude" to latLng.latitude,
|
|
238
|
+
"longitude" to latLng.longitude
|
|
239
|
+
))
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ==================== 地图类型和相机 ====================
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 设置地图类型
|
|
247
|
+
* @param type 地图类型
|
|
248
|
+
*/
|
|
249
|
+
fun setMapType(type: Int) {
|
|
250
|
+
mainHandler.post {
|
|
251
|
+
uiManager.setMapType(type)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 设置初始相机位置
|
|
257
|
+
* @param position 相机位置配置
|
|
258
|
+
*/
|
|
259
|
+
fun setInitialCameraPosition(position: Map<String, Any?>) {
|
|
260
|
+
initialCameraPosition = position
|
|
261
|
+
|
|
262
|
+
// 如果地图已加载,立即应用;否则缓存等待地图加载完成
|
|
263
|
+
if (isMapLoaded) {
|
|
264
|
+
mainHandler.post {
|
|
265
|
+
applyInitialCameraPosition(position)
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
pendingCameraPosition = position
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 实际应用相机位置
|
|
274
|
+
* @param position 相机位置配置
|
|
275
|
+
*/
|
|
276
|
+
private fun applyInitialCameraPosition(position: Map<String, Any?>) {
|
|
277
|
+
cameraManager.setInitialCameraPosition(position)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ==================== UI 控件和手势 ====================
|
|
281
|
+
|
|
282
|
+
/** 设置是否显示缩放控件 */
|
|
283
|
+
fun setShowsZoomControls(show: Boolean) = uiManager.setShowsZoomControls(show)
|
|
284
|
+
/** 设置是否显示指南针 */
|
|
285
|
+
fun setShowsCompass(show: Boolean) = uiManager.setShowsCompass(show)
|
|
286
|
+
/** 设置是否显示比例尺 */
|
|
287
|
+
fun setShowsScale(show: Boolean) = uiManager.setShowsScale(show)
|
|
288
|
+
|
|
289
|
+
/** 设置是否启用缩放手势 */
|
|
290
|
+
fun setZoomEnabled(enabled: Boolean) = uiManager.setZoomEnabled(enabled)
|
|
291
|
+
/** 设置是否启用滚动手势 */
|
|
292
|
+
fun setScrollEnabled(enabled: Boolean) = uiManager.setScrollEnabled(enabled)
|
|
293
|
+
/** 设置是否启用旋转手势 */
|
|
294
|
+
fun setRotateEnabled(enabled: Boolean) = uiManager.setRotateEnabled(enabled)
|
|
295
|
+
/** 设置是否启用倾斜手势 */
|
|
296
|
+
fun setTiltEnabled(enabled: Boolean) = uiManager.setTiltEnabled(enabled)
|
|
297
|
+
|
|
298
|
+
/** 设置最大缩放级别 */
|
|
299
|
+
fun setMaxZoom(maxZoom: Float) = cameraManager.setMaxZoomLevel(maxZoom)
|
|
300
|
+
/** 设置最小缩放级别 */
|
|
301
|
+
fun setMinZoom(minZoom: Float) = cameraManager.setMinZoomLevel(minZoom)
|
|
302
|
+
|
|
303
|
+
/** 设置是否显示用户位置 */
|
|
304
|
+
fun setShowsUserLocation(show: Boolean) {
|
|
305
|
+
mainHandler.post {
|
|
306
|
+
uiManager.setShowsUserLocation(show, followUserLocation)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 设置是否跟随用户位置
|
|
312
|
+
* @param follow 是否跟随
|
|
313
|
+
*/
|
|
314
|
+
fun setFollowUserLocation(follow: Boolean) {
|
|
315
|
+
followUserLocation = follow
|
|
316
|
+
// 如果定位已开启,立即应用新设置
|
|
317
|
+
mainHandler.post {
|
|
318
|
+
if (aMap.isMyLocationEnabled) {
|
|
319
|
+
uiManager.setShowsUserLocation(true, follow)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 设置用户位置样式
|
|
326
|
+
* @param representation 样式配置
|
|
327
|
+
*/
|
|
328
|
+
fun setUserLocationRepresentation(representation: Map<String, Any>) {
|
|
329
|
+
uiManager.setUserLocationRepresentation(representation)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** 设置是否显示交通路况 */
|
|
333
|
+
fun setShowsTraffic(show: Boolean) = uiManager.setShowsTraffic(show)
|
|
334
|
+
/** 设置是否显示建筑物 */
|
|
335
|
+
fun setShowsBuildings(show: Boolean) = uiManager.setShowsBuildings(show)
|
|
336
|
+
/** 设置是否显示室内地图 */
|
|
337
|
+
fun setShowsIndoorMap(show: Boolean) = uiManager.setShowsIndoorMap(show)
|
|
338
|
+
|
|
339
|
+
// ==================== 相机控制方法 ====================
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 移动相机
|
|
343
|
+
* @param position 目标位置
|
|
344
|
+
* @param duration 动画时长(毫秒)
|
|
345
|
+
*/
|
|
346
|
+
fun moveCamera(position: Map<String, Any>, duration: Int) {
|
|
347
|
+
cameraManager.moveCamera(position, duration)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* 获取屏幕坐标对应的地理坐标
|
|
352
|
+
* @param point 屏幕坐标
|
|
353
|
+
* @return 地理坐标
|
|
354
|
+
*/
|
|
355
|
+
fun getLatLng(point: Map<String, Double>): Map<String, Double> {
|
|
356
|
+
return cameraManager.getLatLng(point)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* 设置地图中心点
|
|
361
|
+
* @param center 中心点坐标
|
|
362
|
+
* @param animated 是否动画
|
|
363
|
+
*/
|
|
364
|
+
fun setCenter(center: Map<String, Double>, animated: Boolean) {
|
|
365
|
+
cameraManager.setCenter(center, animated)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 设置地图缩放级别
|
|
370
|
+
* @param zoom 缩放级别
|
|
371
|
+
* @param animated 是否动画
|
|
372
|
+
*/
|
|
373
|
+
fun setZoomLevel(zoom: Float, animated: Boolean) {
|
|
374
|
+
cameraManager.setZoomLevel(zoom, animated)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* 获取当前相机位置
|
|
379
|
+
* @return 相机位置信息
|
|
380
|
+
*/
|
|
381
|
+
fun getCameraPosition(): Map<String, Any> {
|
|
382
|
+
return cameraManager.getCameraPosition()
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ==================== 覆盖物管理 ====================
|
|
386
|
+
|
|
387
|
+
/** 添加圆形覆盖物 */
|
|
388
|
+
fun addCircle(id: String, props: Map<String, Any>) {
|
|
389
|
+
mainHandler.post {
|
|
390
|
+
overlayManager.addCircle(id, props)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** 移除圆形覆盖物 */
|
|
395
|
+
fun removeCircle(id: String) {
|
|
396
|
+
mainHandler.post {
|
|
397
|
+
overlayManager.removeCircle(id)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** 更新圆形覆盖物 */
|
|
402
|
+
fun updateCircle(id: String, props: Map<String, Any>) {
|
|
403
|
+
mainHandler.post {
|
|
404
|
+
overlayManager.updateCircle(id, props)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** 添加标记点 */
|
|
409
|
+
fun addMarker(id: String, props: Map<String, Any>) {
|
|
410
|
+
mainHandler.post {
|
|
411
|
+
overlayManager.addMarker(id, props)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** 移除标记点 */
|
|
416
|
+
fun removeMarker(id: String) {
|
|
417
|
+
mainHandler.post {
|
|
418
|
+
overlayManager.removeMarker(id)
|
|
105
419
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"longitude" to lng
|
|
113
|
-
))
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** 更新标记点 */
|
|
423
|
+
fun updateMarker(id: String, props: Map<String, Any>) {
|
|
424
|
+
mainHandler.post {
|
|
425
|
+
overlayManager.updateMarker(id, props)
|
|
114
426
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** 添加折线 */
|
|
430
|
+
fun addPolyline(id: String, props: Map<String, Any>) {
|
|
431
|
+
mainHandler.post {
|
|
432
|
+
overlayManager.addPolyline(id, props)
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** 移除折线 */
|
|
437
|
+
fun removePolyline(id: String) {
|
|
438
|
+
mainHandler.post {
|
|
439
|
+
overlayManager.removePolyline(id)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** 更新折线 */
|
|
444
|
+
fun updatePolyline(id: String, props: Map<String, Any>) {
|
|
445
|
+
mainHandler.post {
|
|
446
|
+
overlayManager.updatePolyline(id, props)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** 添加多边形 */
|
|
451
|
+
fun addPolygon(id: String, props: Map<String, Any>) {
|
|
452
|
+
mainHandler.post {
|
|
453
|
+
overlayManager.addPolygon(id, props)
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** 移除多边形 */
|
|
458
|
+
fun removePolygon(id: String) {
|
|
459
|
+
mainHandler.post {
|
|
460
|
+
overlayManager.removePolygon(id)
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** 更新多边形 */
|
|
465
|
+
fun updatePolygon(id: String, props: Map<String, Any>) {
|
|
466
|
+
mainHandler.post {
|
|
467
|
+
overlayManager.updatePolygon(id, props)
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ==================== 生命周期方法 ====================
|
|
472
|
+
|
|
473
|
+
/** 恢复地图 */
|
|
474
|
+
@Suppress("unused")
|
|
475
|
+
fun onResume() {
|
|
476
|
+
mapView.onResume()
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** 暂停地图 */
|
|
480
|
+
@Suppress("unused")
|
|
481
|
+
fun onPause() {
|
|
482
|
+
mapView.onPause()
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** 销毁地图 */
|
|
486
|
+
@Suppress("unused")
|
|
487
|
+
fun onDestroy() {
|
|
488
|
+
// 清理 Handler 回调,防止内存泄露
|
|
489
|
+
mainHandler.removeCallbacksAndMessages(null)
|
|
490
|
+
|
|
491
|
+
// 清理地图监听器
|
|
492
|
+
aMap.setOnMapClickListener(null)
|
|
493
|
+
aMap.setOnMapLongClickListener(null)
|
|
494
|
+
aMap.setOnMapLoadedListener(null)
|
|
495
|
+
|
|
496
|
+
// 清理覆盖物
|
|
497
|
+
overlayManager.clear()
|
|
498
|
+
|
|
499
|
+
// 清理 MarkerView 列表
|
|
500
|
+
markerViews.clear()
|
|
501
|
+
|
|
502
|
+
// 销毁地图
|
|
503
|
+
mapView.onDestroy()
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** 保存实例状态 */
|
|
507
|
+
@Suppress("unused")
|
|
508
|
+
fun onSaveInstanceState(outState: android.os.Bundle) {
|
|
509
|
+
mapView.onSaveInstanceState(outState)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* 存储 MarkerView 引用,因为它们不在视图层级中
|
|
514
|
+
*/
|
|
515
|
+
private val markerViews = mutableListOf<MarkerView>()
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* 添加子视图时自动连接到地图
|
|
519
|
+
*
|
|
520
|
+
* 关键修复:MarkerView 不进入视图层级,但要确保 React Native 追踪正确
|
|
521
|
+
*/
|
|
522
|
+
override fun addView(child: View?, index: Int) {
|
|
523
|
+
if (child is MarkerView) {
|
|
524
|
+
child.setMap(aMap)
|
|
525
|
+
markerViews.add(child)
|
|
526
|
+
return
|
|
121
527
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"longitude" to lng
|
|
127
|
-
))
|
|
528
|
+
|
|
529
|
+
if (child is com.amap.api.maps.MapView) {
|
|
530
|
+
super.addView(child, index)
|
|
531
|
+
return
|
|
128
532
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
533
|
+
|
|
534
|
+
super.addView(child, index)
|
|
535
|
+
|
|
536
|
+
child?.let {
|
|
537
|
+
when (it) {
|
|
538
|
+
is PolylineView -> it.setMap(aMap)
|
|
539
|
+
is PolygonView -> it.setMap(aMap)
|
|
540
|
+
is CircleView -> it.setMap(aMap)
|
|
541
|
+
is HeatMapView -> it.setMap(aMap)
|
|
542
|
+
is MultiPointView -> it.setMap(aMap)
|
|
543
|
+
is ClusterView -> it.setMap(aMap)
|
|
544
|
+
}
|
|
135
545
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* 移除子视图
|
|
550
|
+
*/
|
|
551
|
+
override fun removeView(child: View?) {
|
|
552
|
+
if (child is MarkerView) {
|
|
553
|
+
markerViews.remove(child)
|
|
554
|
+
child.removeMarker()
|
|
555
|
+
return
|
|
142
556
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"
|
|
148
|
-
))
|
|
557
|
+
|
|
558
|
+
try {
|
|
559
|
+
super.removeView(child)
|
|
560
|
+
} catch (e: Exception) {
|
|
561
|
+
Log.e(TAG, "removeView 异常", e)
|
|
149
562
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* 按索引移除视图
|
|
567
|
+
*
|
|
568
|
+
* 终极修复:完全忽略所有无效的移除请求
|
|
569
|
+
*/
|
|
570
|
+
override fun removeViewAt(index: Int) {
|
|
571
|
+
try {
|
|
572
|
+
val actualChildCount = super.getChildCount()
|
|
573
|
+
|
|
574
|
+
if (index >= actualChildCount) {
|
|
575
|
+
val markerIndex = index - actualChildCount
|
|
576
|
+
if (markerIndex >= 0 && markerIndex < markerViews.size) {
|
|
577
|
+
val markerView = markerViews.removeAt(markerIndex)
|
|
578
|
+
markerView.removeMarker()
|
|
579
|
+
return
|
|
580
|
+
} else {
|
|
581
|
+
return
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (actualChildCount == 0) {
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
val child = super.getChildAt(index)
|
|
590
|
+
|
|
591
|
+
if (child is com.amap.api.maps.MapView) {
|
|
592
|
+
Log.e(TAG, "阻止移除 MapView")
|
|
593
|
+
return
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (child is MarkerView) {
|
|
597
|
+
removeView(child)
|
|
598
|
+
return
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
super.removeViewAt(index)
|
|
602
|
+
|
|
603
|
+
} catch (e: IllegalArgumentException) {
|
|
604
|
+
// 忽略索引异常
|
|
605
|
+
} catch (e: IndexOutOfBoundsException) {
|
|
606
|
+
// 忽略越界异常
|
|
607
|
+
} catch (e: Exception) {
|
|
608
|
+
Log.e(TAG, "移除视图异常", e)
|
|
156
609
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
isMapLoaded = true
|
|
168
|
-
|
|
169
|
-
// 应用缓存的 Props
|
|
170
|
-
if (mapType != 0) {
|
|
171
|
-
setMapType(mapType)
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
private fun checkDeclarativePolylinePress(latLng: LatLng): Boolean {
|
|
613
|
+
for (i in 0 until childCount) {
|
|
614
|
+
val child = getChildAt(i)
|
|
615
|
+
if (child is PolylineView) {
|
|
616
|
+
if (child.checkPress(latLng)) {
|
|
617
|
+
return true
|
|
618
|
+
}
|
|
619
|
+
}
|
|
172
620
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
621
|
+
return false
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private fun checkDeclarativePolygonPress(latLng: LatLng): Boolean {
|
|
625
|
+
for (i in 0 until childCount) {
|
|
626
|
+
val child = getChildAt(i)
|
|
627
|
+
if (child is PolygonView) {
|
|
628
|
+
if (child.checkPress(latLng)) {
|
|
629
|
+
return true
|
|
630
|
+
}
|
|
631
|
+
}
|
|
178
632
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
private fun setupMapListeners() {
|
|
191
|
-
aMap.setOnMapClickListener { latLng ->
|
|
192
|
-
// 检查声明式 PolylineView
|
|
193
|
-
if (checkDeclarativePolylinePress(latLng)) {
|
|
194
|
-
return@setOnMapClickListener
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// 检查声明式 PolygonView
|
|
198
|
-
if (checkDeclarativePolygonPress(latLng)) {
|
|
199
|
-
return@setOnMapClickListener
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// 检查声明式 CircleView
|
|
203
|
-
if (checkDeclarativeCirclePress(latLng)) {
|
|
204
|
-
return@setOnMapClickListener
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// 检查命令式圆形
|
|
208
|
-
val circleId = overlayManager.checkCirclePress(latLng)
|
|
209
|
-
if (circleId != null) {
|
|
210
|
-
overlayManager.onCirclePress?.invoke(circleId, latLng.latitude, latLng.longitude)
|
|
211
|
-
return@setOnMapClickListener
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// 检查命令式多边形
|
|
215
|
-
val polygonId = overlayManager.checkPolygonPress(latLng)
|
|
216
|
-
if (polygonId != null) {
|
|
217
|
-
overlayManager.onPolygonPress?.invoke(polygonId, latLng.latitude, latLng.longitude)
|
|
218
|
-
return@setOnMapClickListener
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// 检查命令式折线
|
|
222
|
-
val polylineId = overlayManager.checkPolylinePress(latLng)
|
|
223
|
-
if (polylineId != null) {
|
|
224
|
-
overlayManager.onPolylinePress?.invoke(polylineId, latLng.latitude, latLng.longitude)
|
|
225
|
-
return@setOnMapClickListener
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// 如果都没点击,触发地图点击事件
|
|
229
|
-
onMapPress(mapOf(
|
|
230
|
-
"latitude" to latLng.latitude,
|
|
231
|
-
"longitude" to latLng.longitude
|
|
232
|
-
))
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
aMap.setOnMapLongClickListener { latLng ->
|
|
236
|
-
onMapLongPress(mapOf(
|
|
237
|
-
"latitude" to latLng.latitude,
|
|
238
|
-
"longitude" to latLng.longitude
|
|
239
|
-
))
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ==================== 地图类型和相机 ====================
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* 设置地图类型
|
|
247
|
-
* @param type 地图类型
|
|
248
|
-
*/
|
|
249
|
-
fun setMapType(type: Int) {
|
|
250
|
-
mainHandler.post {
|
|
251
|
-
uiManager.setMapType(type)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* 设置初始相机位置
|
|
257
|
-
* @param position 相机位置配置
|
|
258
|
-
*/
|
|
259
|
-
fun setInitialCameraPosition(position: Map<String, Any?>) {
|
|
260
|
-
initialCameraPosition = position
|
|
261
|
-
|
|
262
|
-
// 如果地图已加载,立即应用;否则缓存等待地图加载完成
|
|
263
|
-
if (isMapLoaded) {
|
|
264
|
-
mainHandler.post {
|
|
265
|
-
applyInitialCameraPosition(position)
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
pendingCameraPosition = position
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* 实际应用相机位置
|
|
274
|
-
* @param position 相机位置配置
|
|
275
|
-
*/
|
|
276
|
-
private fun applyInitialCameraPosition(position: Map<String, Any?>) {
|
|
277
|
-
cameraManager.setInitialCameraPosition(position)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// ==================== UI 控件和手势 ====================
|
|
281
|
-
|
|
282
|
-
/** 设置是否显示缩放控件 */
|
|
283
|
-
fun setShowsZoomControls(show: Boolean) = uiManager.setShowsZoomControls(show)
|
|
284
|
-
/** 设置是否显示指南针 */
|
|
285
|
-
fun setShowsCompass(show: Boolean) = uiManager.setShowsCompass(show)
|
|
286
|
-
/** 设置是否显示比例尺 */
|
|
287
|
-
fun setShowsScale(show: Boolean) = uiManager.setShowsScale(show)
|
|
288
|
-
|
|
289
|
-
/** 设置是否启用缩放手势 */
|
|
290
|
-
fun setZoomEnabled(enabled: Boolean) = uiManager.setZoomEnabled(enabled)
|
|
291
|
-
/** 设置是否启用滚动手势 */
|
|
292
|
-
fun setScrollEnabled(enabled: Boolean) = uiManager.setScrollEnabled(enabled)
|
|
293
|
-
/** 设置是否启用旋转手势 */
|
|
294
|
-
fun setRotateEnabled(enabled: Boolean) = uiManager.setRotateEnabled(enabled)
|
|
295
|
-
/** 设置是否启用倾斜手势 */
|
|
296
|
-
fun setTiltEnabled(enabled: Boolean) = uiManager.setTiltEnabled(enabled)
|
|
297
|
-
|
|
298
|
-
/** 设置最大缩放级别 */
|
|
299
|
-
fun setMaxZoom(maxZoom: Float) = cameraManager.setMaxZoomLevel(maxZoom)
|
|
300
|
-
/** 设置最小缩放级别 */
|
|
301
|
-
fun setMinZoom(minZoom: Float) = cameraManager.setMinZoomLevel(minZoom)
|
|
302
|
-
|
|
303
|
-
/** 设置是否显示用户位置 */
|
|
304
|
-
fun setShowsUserLocation(show: Boolean) {
|
|
305
|
-
mainHandler.post {
|
|
306
|
-
uiManager.setShowsUserLocation(show, followUserLocation)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* 设置是否跟随用户位置
|
|
312
|
-
* @param follow 是否跟随
|
|
313
|
-
*/
|
|
314
|
-
fun setFollowUserLocation(follow: Boolean) {
|
|
315
|
-
followUserLocation = follow
|
|
316
|
-
// 如果定位已开启,立即应用新设置
|
|
317
|
-
mainHandler.post {
|
|
318
|
-
if (aMap.isMyLocationEnabled) {
|
|
319
|
-
uiManager.setShowsUserLocation(true, follow)
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* 设置用户位置样式
|
|
326
|
-
* @param representation 样式配置
|
|
327
|
-
*/
|
|
328
|
-
fun setUserLocationRepresentation(representation: Map<String, Any>) {
|
|
329
|
-
uiManager.setUserLocationRepresentation(representation)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/** 设置是否显示交通路况 */
|
|
333
|
-
fun setShowsTraffic(show: Boolean) = uiManager.setShowsTraffic(show)
|
|
334
|
-
/** 设置是否显示建筑物 */
|
|
335
|
-
fun setShowsBuildings(show: Boolean) = uiManager.setShowsBuildings(show)
|
|
336
|
-
/** 设置是否显示室内地图 */
|
|
337
|
-
fun setShowsIndoorMap(show: Boolean) = uiManager.setShowsIndoorMap(show)
|
|
338
|
-
|
|
339
|
-
// ==================== 相机控制方法 ====================
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* 移动相机
|
|
343
|
-
* @param position 目标位置
|
|
344
|
-
* @param duration 动画时长(毫秒)
|
|
345
|
-
*/
|
|
346
|
-
fun moveCamera(position: Map<String, Any>, duration: Int) {
|
|
347
|
-
cameraManager.moveCamera(position, duration)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* 获取屏幕坐标对应的地理坐标
|
|
352
|
-
* @param point 屏幕坐标
|
|
353
|
-
* @return 地理坐标
|
|
354
|
-
*/
|
|
355
|
-
fun getLatLng(point: Map<String, Double>): Map<String, Double> {
|
|
356
|
-
return cameraManager.getLatLng(point)
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* 设置地图中心点
|
|
361
|
-
* @param center 中心点坐标
|
|
362
|
-
* @param animated 是否动画
|
|
363
|
-
*/
|
|
364
|
-
fun setCenter(center: Map<String, Double>, animated: Boolean) {
|
|
365
|
-
cameraManager.setCenter(center, animated)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* 设置地图缩放级别
|
|
370
|
-
* @param zoom 缩放级别
|
|
371
|
-
* @param animated 是否动画
|
|
372
|
-
*/
|
|
373
|
-
fun setZoomLevel(zoom: Float, animated: Boolean) {
|
|
374
|
-
cameraManager.setZoomLevel(zoom, animated)
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* 获取当前相机位置
|
|
379
|
-
* @return 相机位置信息
|
|
380
|
-
*/
|
|
381
|
-
fun getCameraPosition(): Map<String, Any> {
|
|
382
|
-
return cameraManager.getCameraPosition()
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// ==================== 覆盖物管理 ====================
|
|
386
|
-
|
|
387
|
-
/** 添加圆形覆盖物 */
|
|
388
|
-
fun addCircle(id: String, props: Map<String, Any>) {
|
|
389
|
-
mainHandler.post {
|
|
390
|
-
overlayManager.addCircle(id, props)
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/** 移除圆形覆盖物 */
|
|
395
|
-
fun removeCircle(id: String) {
|
|
396
|
-
mainHandler.post {
|
|
397
|
-
overlayManager.removeCircle(id)
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/** 更新圆形覆盖物 */
|
|
402
|
-
fun updateCircle(id: String, props: Map<String, Any>) {
|
|
403
|
-
mainHandler.post {
|
|
404
|
-
overlayManager.updateCircle(id, props)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/** 添加标记点 */
|
|
409
|
-
fun addMarker(id: String, props: Map<String, Any>) {
|
|
410
|
-
mainHandler.post {
|
|
411
|
-
overlayManager.addMarker(id, props)
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/** 移除标记点 */
|
|
416
|
-
fun removeMarker(id: String) {
|
|
417
|
-
mainHandler.post {
|
|
418
|
-
overlayManager.removeMarker(id)
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/** 更新标记点 */
|
|
423
|
-
fun updateMarker(id: String, props: Map<String, Any>) {
|
|
424
|
-
mainHandler.post {
|
|
425
|
-
overlayManager.updateMarker(id, props)
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/** 添加折线 */
|
|
430
|
-
fun addPolyline(id: String, props: Map<String, Any>) {
|
|
431
|
-
mainHandler.post {
|
|
432
|
-
overlayManager.addPolyline(id, props)
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/** 移除折线 */
|
|
437
|
-
fun removePolyline(id: String) {
|
|
438
|
-
mainHandler.post {
|
|
439
|
-
overlayManager.removePolyline(id)
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/** 更新折线 */
|
|
444
|
-
fun updatePolyline(id: String, props: Map<String, Any>) {
|
|
445
|
-
mainHandler.post {
|
|
446
|
-
overlayManager.updatePolyline(id, props)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/** 添加多边形 */
|
|
451
|
-
fun addPolygon(id: String, props: Map<String, Any>) {
|
|
452
|
-
mainHandler.post {
|
|
453
|
-
overlayManager.addPolygon(id, props)
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/** 移除多边形 */
|
|
458
|
-
fun removePolygon(id: String) {
|
|
459
|
-
mainHandler.post {
|
|
460
|
-
overlayManager.removePolygon(id)
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/** 更新多边形 */
|
|
465
|
-
fun updatePolygon(id: String, props: Map<String, Any>) {
|
|
466
|
-
mainHandler.post {
|
|
467
|
-
overlayManager.updatePolygon(id, props)
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// ==================== 生命周期方法 ====================
|
|
472
|
-
|
|
473
|
-
/** 恢复地图 */
|
|
474
|
-
@Suppress("unused")
|
|
475
|
-
fun onResume() {
|
|
476
|
-
mapView.onResume()
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/** 暂停地图 */
|
|
480
|
-
@Suppress("unused")
|
|
481
|
-
fun onPause() {
|
|
482
|
-
mapView.onPause()
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/** 销毁地图 */
|
|
486
|
-
@Suppress("unused")
|
|
487
|
-
fun onDestroy() {
|
|
488
|
-
// 清理 Handler 回调,防止内存泄露
|
|
489
|
-
mainHandler.removeCallbacksAndMessages(null)
|
|
490
|
-
|
|
491
|
-
// 清理地图监听器
|
|
492
|
-
aMap.setOnMapClickListener(null)
|
|
493
|
-
aMap.setOnMapLongClickListener(null)
|
|
494
|
-
aMap.setOnMapLoadedListener(null)
|
|
495
|
-
|
|
496
|
-
// 清理覆盖物
|
|
497
|
-
overlayManager.clear()
|
|
498
|
-
|
|
499
|
-
// 清理 MarkerView 列表
|
|
500
|
-
markerViews.clear()
|
|
501
|
-
|
|
502
|
-
// 销毁地图
|
|
503
|
-
mapView.onDestroy()
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/** 保存实例状态 */
|
|
507
|
-
@Suppress("unused")
|
|
508
|
-
fun onSaveInstanceState(outState: android.os.Bundle) {
|
|
509
|
-
mapView.onSaveInstanceState(outState)
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* 存储 MarkerView 引用,因为它们不在视图层级中
|
|
514
|
-
*/
|
|
515
|
-
private val markerViews = mutableListOf<MarkerView>()
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* 添加子视图时自动连接到地图
|
|
519
|
-
*
|
|
520
|
-
* 关键修复:MarkerView 不进入视图层级,但要确保 React Native 追踪正确
|
|
521
|
-
*/
|
|
522
|
-
override fun addView(child: View?, index: Int) {
|
|
523
|
-
if (child is MarkerView) {
|
|
524
|
-
// ✅ MarkerView 不加入视图层级
|
|
525
|
-
child.setMap(aMap)
|
|
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 已添加")
|
|
536
|
-
return
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
super.addView(child, index)
|
|
540
|
-
|
|
541
|
-
// 自动将地图实例传递给其他覆盖物子视图
|
|
542
|
-
child?.let {
|
|
543
|
-
when (it) {
|
|
544
|
-
is PolylineView -> it.setMap(aMap)
|
|
545
|
-
is PolygonView -> it.setMap(aMap)
|
|
546
|
-
is CircleView -> it.setMap(aMap)
|
|
547
|
-
is HeatMapView -> it.setMap(aMap)
|
|
548
|
-
is MultiPointView -> it.setMap(aMap)
|
|
549
|
-
is ClusterView -> it.setMap(aMap)
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* 移除子视图
|
|
556
|
-
*/
|
|
557
|
-
override fun removeView(child: View?) {
|
|
558
|
-
if (child is MarkerView) {
|
|
559
|
-
// 从 MarkerView 列表中移除并清理
|
|
560
|
-
markerViews.remove(child)
|
|
561
|
-
child.removeMarker()
|
|
562
|
-
Log.d(TAG, "✅ MarkerView 已清理,当前 markerViews 数量: ${markerViews.size}")
|
|
563
|
-
return
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
try {
|
|
567
|
-
super.removeView(child)
|
|
568
|
-
} catch (e: Exception) {
|
|
569
|
-
Log.e(TAG, "removeView 异常", e)
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
/**
|
|
574
|
-
* 按索引移除视图
|
|
575
|
-
*
|
|
576
|
-
* 终极修复:完全忽略所有无效的移除请求
|
|
577
|
-
*/
|
|
578
|
-
override fun removeViewAt(index: Int) {
|
|
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
|
-
// 正常移除其他视图
|
|
614
|
-
super.removeViewAt(index)
|
|
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)
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
private fun checkDeclarativePolylinePress(latLng: LatLng): Boolean {
|
|
630
|
-
for (i in 0 until childCount) {
|
|
631
|
-
val child = getChildAt(i)
|
|
632
|
-
if (child is PolylineView) {
|
|
633
|
-
if (child.checkPress(latLng)) {
|
|
634
|
-
return true
|
|
633
|
+
return false
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private fun checkDeclarativeCirclePress(latLng: LatLng): Boolean {
|
|
637
|
+
for (i in 0 until childCount) {
|
|
638
|
+
val child = getChildAt(i)
|
|
639
|
+
if (child is CircleView) {
|
|
640
|
+
if (child.checkPress(latLng)) {
|
|
641
|
+
return true
|
|
642
|
+
}
|
|
643
|
+
}
|
|
635
644
|
}
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
645
|
+
return false
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
649
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* 重写 getChildCount,返回 React Native 期望的子视图数量
|
|
654
|
+
* 包括实际视图层级中的子视图 + MarkerView 数量
|
|
655
|
+
*/
|
|
656
|
+
override fun getChildCount(): Int {
|
|
657
|
+
return super.getChildCount() + markerViews.size
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* 重写 getChildAt,处理 MarkerView 的索引映射
|
|
662
|
+
* 当索引超出实际子视图数量时,返回对应的 MarkerView
|
|
663
|
+
*/
|
|
664
|
+
override fun getChildAt(index: Int): View? {
|
|
665
|
+
val actualCount = super.getChildCount()
|
|
666
|
+
|
|
667
|
+
if (index < actualCount) {
|
|
668
|
+
return super.getChildAt(index)
|
|
647
669
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
private fun checkDeclarativeCirclePress(latLng: LatLng): Boolean {
|
|
654
|
-
for (i in 0 until childCount) {
|
|
655
|
-
val child = getChildAt(i)
|
|
656
|
-
if (child is CircleView) {
|
|
657
|
-
if (child.checkPress(latLng)) {
|
|
658
|
-
return true
|
|
670
|
+
|
|
671
|
+
val markerIndex = index - actualCount
|
|
672
|
+
if (markerIndex >= 0 && markerIndex < markerViews.size) {
|
|
673
|
+
return markerViews[markerIndex]
|
|
659
674
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
666
|
-
super.onLayout(changed, left, top, right, bottom)
|
|
667
|
-
}
|
|
675
|
+
|
|
676
|
+
return null
|
|
677
|
+
}
|
|
668
678
|
}
|