expo-gaode-map 1.1.7 → 2.0.0-alpha.1
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/README.en.md +32 -46
- package/README.md +51 -71
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +37 -237
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +1 -49
- package/android/src/main/java/expo/modules/gaodemap/managers/CameraManager.kt +30 -7
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +1 -0
- package/android/src/main/java/expo/modules/gaodemap/modules/LocationManager.kt +10 -1
- package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +38 -14
- package/android/src/main/java/expo/modules/gaodemap/overlays/CircleViewModule.kt +3 -3
- package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +8 -1
- package/android/src/main/java/expo/modules/gaodemap/overlays/HeatMapView.kt +4 -1
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +322 -93
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +11 -3
- package/android/src/main/java/expo/modules/gaodemap/overlays/MultiPointView.kt +4 -1
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonView.kt +25 -11
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonViewModule.kt +3 -3
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineView.kt +20 -10
- package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineViewModule.kt +6 -2
- package/build/ExpoGaodeMap.types.d.ts +27 -6
- package/build/ExpoGaodeMap.types.d.ts.map +1 -1
- package/build/ExpoGaodeMap.types.js +3 -0
- package/build/ExpoGaodeMap.types.js.map +1 -1
- package/build/ExpoGaodeMapModule.d.ts +157 -10
- package/build/ExpoGaodeMapModule.d.ts.map +1 -1
- package/build/ExpoGaodeMapModule.js +4 -0
- package/build/ExpoGaodeMapModule.js.map +1 -1
- package/build/ExpoGaodeMapView.d.ts +1 -17
- package/build/ExpoGaodeMapView.d.ts.map +1 -1
- package/build/ExpoGaodeMapView.js +4 -209
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/overlays/Circle.d.ts +10 -1
- package/build/components/overlays/Circle.d.ts.map +1 -1
- package/build/components/overlays/Circle.js +11 -86
- package/build/components/overlays/Circle.js.map +1 -1
- package/build/components/overlays/Cluster.d.ts.map +1 -1
- package/build/components/overlays/Cluster.js.map +1 -1
- package/build/components/overlays/Marker.d.ts +13 -1
- package/build/components/overlays/Marker.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +51 -115
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/components/overlays/Polygon.d.ts +7 -15
- package/build/components/overlays/Polygon.d.ts.map +1 -1
- package/build/components/overlays/Polygon.js +10 -80
- package/build/components/overlays/Polygon.js.map +1 -1
- package/build/components/overlays/Polyline.d.ts +7 -14
- package/build/components/overlays/Polyline.d.ts.map +1 -1
- package/build/components/overlays/Polyline.js +9 -66
- package/build/components/overlays/Polyline.js.map +1 -1
- package/build/index.d.ts +1 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -10
- package/build/index.js.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js.map +1 -1
- package/build/types/map-view.types.d.ts +0 -76
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +11 -16
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/docs/API.en.md +1 -21
- package/docs/API.md +84 -56
- package/docs/EXAMPLES.en.md +0 -48
- package/docs/EXAMPLES.md +49 -102
- package/docs/INITIALIZATION.md +59 -71
- package/docs/MIGRATION.md +423 -0
- package/ios/ExpoGaodeMapView.swift +317 -258
- package/ios/ExpoGaodeMapViewModule.swift +3 -50
- package/ios/managers/CameraManager.swift +23 -2
- package/ios/managers/UIManager.swift +10 -5
- package/ios/modules/LocationManager.swift +10 -0
- package/ios/overlays/CircleView.swift +98 -19
- package/ios/overlays/CircleViewModule.swift +21 -0
- package/ios/overlays/ClusterView.swift +33 -4
- package/ios/overlays/HeatMapView.swift +16 -4
- package/ios/overlays/MarkerView.swift +235 -146
- package/ios/overlays/MarkerViewModule.swift +7 -3
- package/ios/overlays/MultiPointView.swift +30 -1
- package/ios/overlays/PolygonView.swift +63 -12
- package/ios/overlays/PolygonViewModule.swift +17 -0
- package/ios/overlays/PolylineView.swift +95 -25
- package/ios/overlays/PolylineViewModule.swift +17 -8
- package/ios/utils/PermissionManager.swift +9 -14
- package/package.json +4 -3
- package/src/ExpoGaodeMap.types.ts +28 -3
- package/src/ExpoGaodeMapModule.ts +201 -12
- package/src/ExpoGaodeMapView.tsx +11 -225
- package/src/components/overlays/Circle.tsx +12 -104
- package/src/components/overlays/Cluster.tsx +0 -1
- package/src/components/overlays/Marker.tsx +63 -138
- package/src/components/overlays/Polygon.tsx +12 -92
- package/src/components/overlays/Polyline.tsx +11 -77
- package/src/index.ts +4 -29
- package/src/types/index.ts +1 -1
- package/src/types/map-view.types.ts +1 -69
- package/src/types/overlays.types.ts +11 -16
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +0 -574
- package/build/modules/AMapLocation.d.ts +0 -78
- package/build/modules/AMapLocation.d.ts.map +0 -1
- package/build/modules/AMapLocation.js +0 -132
- package/build/modules/AMapLocation.js.map +0 -1
- package/build/modules/AMapPermissions.d.ts +0 -29
- package/build/modules/AMapPermissions.d.ts.map +0 -1
- package/build/modules/AMapPermissions.js +0 -23
- package/build/modules/AMapPermissions.js.map +0 -1
- package/build/modules/AMapSDK.d.ts +0 -22
- package/build/modules/AMapSDK.d.ts.map +0 -1
- package/build/modules/AMapSDK.js +0 -25
- package/build/modules/AMapSDK.js.map +0 -1
- package/build/modules/AMapView.d.ts +0 -44
- package/build/modules/AMapView.d.ts.map +0 -1
- package/build/modules/AMapView.js +0 -65
- package/build/modules/AMapView.js.map +0 -1
- package/ios/managers/OverlayManager.swift +0 -522
- package/src/modules/AMapLocation.ts +0 -165
- package/src/modules/AMapPermissions.ts +0 -41
- package/src/modules/AMapSDK.ts +0 -31
- package/src/modules/AMapView.ts +0 -72
- package/test/ClockMapView.tsx +0 -532
- package/test/useMap.ts +0 -1360
|
@@ -3,6 +3,7 @@ package expo.modules.gaodemap.overlays
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.graphics.Bitmap
|
|
6
|
+
import android.graphics.BitmapFactory
|
|
6
7
|
import android.graphics.Canvas
|
|
7
8
|
import android.graphics.Color
|
|
8
9
|
import android.graphics.Paint
|
|
@@ -18,6 +19,11 @@ import com.amap.api.maps.model.MarkerOptions
|
|
|
18
19
|
import expo.modules.kotlin.AppContext
|
|
19
20
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
20
21
|
import expo.modules.kotlin.views.ExpoView
|
|
22
|
+
import java.io.File
|
|
23
|
+
import java.io.InputStream
|
|
24
|
+
import java.net.HttpURLConnection
|
|
25
|
+
import java.net.URL
|
|
26
|
+
import kotlin.concurrent.thread
|
|
21
27
|
|
|
22
28
|
class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
23
29
|
|
|
@@ -91,17 +97,16 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
91
97
|
try {
|
|
92
98
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
|
93
99
|
} catch (e: Exception) {
|
|
94
|
-
android.util.Log.e("MarkerView", "onMeasure 失败", e)
|
|
95
100
|
throw e
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
|
|
99
|
-
private val
|
|
100
|
-
private val
|
|
101
|
-
private val
|
|
102
|
-
private val
|
|
104
|
+
private val onMarkerPress by EventDispatcher()
|
|
105
|
+
private val onMarkerDragStart by EventDispatcher()
|
|
106
|
+
private val onMarkerDrag by EventDispatcher()
|
|
107
|
+
private val onMarkerDragEnd by EventDispatcher()
|
|
103
108
|
|
|
104
|
-
|
|
109
|
+
internal var marker: Marker? = null
|
|
105
110
|
private var aMap: AMap? = null
|
|
106
111
|
private var pendingPosition: LatLng? = null
|
|
107
112
|
private var pendingLatitude: Double? = null // 临时存储纬度
|
|
@@ -111,6 +116,18 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
111
116
|
private var customViewWidth: Int = 0 // 用于自定义视图(children)的宽度
|
|
112
117
|
private var customViewHeight: Int = 0 // 用于自定义视图(children)的高度
|
|
113
118
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
119
|
+
private var isRemoving = false // 标记是否正在被移除
|
|
120
|
+
|
|
121
|
+
// 缓存属性,在 marker 创建前保存
|
|
122
|
+
private var pendingTitle: String? = null
|
|
123
|
+
private var pendingSnippet: String? = null
|
|
124
|
+
private var pendingDraggable: Boolean? = null
|
|
125
|
+
private var pendingOpacity: Float? = null
|
|
126
|
+
private var pendingFlat: Boolean? = null
|
|
127
|
+
private var pendingZIndex: Float? = null
|
|
128
|
+
private var pendingAnchor: Pair<Float, Float>? = null
|
|
129
|
+
private var pendingIconUri: String? = null
|
|
130
|
+
private var pendingPinColor: String? = null
|
|
114
131
|
|
|
115
132
|
/**
|
|
116
133
|
* 设置地图实例
|
|
@@ -142,7 +159,6 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
142
159
|
fun setLatitude(lat: Double) {
|
|
143
160
|
try {
|
|
144
161
|
if (lat < -90 || lat > 90) {
|
|
145
|
-
android.util.Log.e("MarkerView", "纬度超出有效范围: $lat")
|
|
146
162
|
return
|
|
147
163
|
}
|
|
148
164
|
|
|
@@ -151,7 +167,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
151
167
|
updatePosition(lat, lng)
|
|
152
168
|
}
|
|
153
169
|
} catch (e: Exception) {
|
|
154
|
-
|
|
170
|
+
// 忽略异常
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
173
|
|
|
@@ -161,7 +177,6 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
161
177
|
fun setLongitude(lng: Double) {
|
|
162
178
|
try {
|
|
163
179
|
if (lng < -180 || lng > 180) {
|
|
164
|
-
android.util.Log.e("MarkerView", "经度超出有效范围: $lng")
|
|
165
180
|
return
|
|
166
181
|
}
|
|
167
182
|
|
|
@@ -170,7 +185,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
170
185
|
updatePosition(lat, lng)
|
|
171
186
|
}
|
|
172
187
|
} catch (e: Exception) {
|
|
173
|
-
|
|
188
|
+
// 忽略异常
|
|
174
189
|
}
|
|
175
190
|
}
|
|
176
191
|
|
|
@@ -197,7 +212,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
197
212
|
}
|
|
198
213
|
}
|
|
199
214
|
} catch (e: Exception) {
|
|
200
|
-
|
|
215
|
+
// 忽略异常
|
|
201
216
|
}
|
|
202
217
|
}
|
|
203
218
|
|
|
@@ -210,18 +225,16 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
210
225
|
val lng = position["longitude"]
|
|
211
226
|
|
|
212
227
|
if (lat == null || lng == null) {
|
|
213
|
-
android.util.Log.e("MarkerView", "无效的位置数据")
|
|
214
228
|
return
|
|
215
229
|
}
|
|
216
230
|
|
|
217
231
|
if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
|
|
218
|
-
android.util.Log.e("MarkerView", "坐标超出有效范围")
|
|
219
232
|
return
|
|
220
233
|
}
|
|
221
234
|
|
|
222
235
|
updatePosition(lat, lng)
|
|
223
236
|
} catch (e: Exception) {
|
|
224
|
-
|
|
237
|
+
// 忽略异常
|
|
225
238
|
}
|
|
226
239
|
}
|
|
227
240
|
|
|
@@ -229,20 +242,35 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
229
242
|
* 设置标题
|
|
230
243
|
*/
|
|
231
244
|
fun setTitle(title: String) {
|
|
232
|
-
|
|
245
|
+
pendingTitle = title
|
|
246
|
+
marker?.let {
|
|
247
|
+
it.title = title
|
|
248
|
+
// 如果信息窗口正在显示,刷新它
|
|
249
|
+
if (it.isInfoWindowShown) {
|
|
250
|
+
it.showInfoWindow()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
233
253
|
}
|
|
234
254
|
|
|
235
255
|
/**
|
|
236
256
|
* 设置描述
|
|
237
257
|
*/
|
|
238
258
|
fun setDescription(description: String) {
|
|
239
|
-
|
|
259
|
+
pendingSnippet = description
|
|
260
|
+
marker?.let {
|
|
261
|
+
it.snippet = description
|
|
262
|
+
// 如果信息窗口正在显示,刷新它
|
|
263
|
+
if (it.isInfoWindowShown) {
|
|
264
|
+
it.showInfoWindow()
|
|
265
|
+
}
|
|
266
|
+
}
|
|
240
267
|
}
|
|
241
268
|
|
|
242
269
|
/**
|
|
243
270
|
* 设置是否可拖拽
|
|
244
271
|
*/
|
|
245
272
|
fun setDraggable(draggable: Boolean) {
|
|
273
|
+
pendingDraggable = draggable
|
|
246
274
|
marker?.let { it.isDraggable = draggable }
|
|
247
275
|
}
|
|
248
276
|
|
|
@@ -263,6 +291,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
263
291
|
* 设置透明度
|
|
264
292
|
*/
|
|
265
293
|
fun setOpacity(opacity: Float) {
|
|
294
|
+
pendingOpacity = opacity
|
|
266
295
|
marker?.let { it.alpha = opacity }
|
|
267
296
|
}
|
|
268
297
|
|
|
@@ -280,13 +309,15 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
280
309
|
fun setAnchor(anchor: Map<String, Float>) {
|
|
281
310
|
val x = anchor["x"] ?: 0.5f
|
|
282
311
|
val y = anchor["y"] ?: 1.0f
|
|
283
|
-
|
|
312
|
+
pendingAnchor = Pair(x, y)
|
|
313
|
+
marker?.setAnchor(x, y)
|
|
284
314
|
}
|
|
285
315
|
|
|
286
316
|
/**
|
|
287
317
|
* 设置是否平贴地图
|
|
288
318
|
*/
|
|
289
319
|
fun setFlat(flat: Boolean) {
|
|
320
|
+
pendingFlat = flat
|
|
290
321
|
marker?.let { it.isFlat = flat }
|
|
291
322
|
}
|
|
292
323
|
|
|
@@ -294,37 +325,183 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
294
325
|
* 设置图标
|
|
295
326
|
*/
|
|
296
327
|
fun setMarkerIcon(iconUri: String?) {
|
|
328
|
+
pendingIconUri = iconUri
|
|
297
329
|
iconUri?.let {
|
|
298
|
-
|
|
299
|
-
|
|
330
|
+
marker?.let { m ->
|
|
331
|
+
loadAndSetIcon(it, m)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 加载并设置图标
|
|
338
|
+
* 支持: http/https 网络图片, file:// 本地文件, 本地资源名
|
|
339
|
+
*/
|
|
340
|
+
private fun loadAndSetIcon(iconUri: String, marker: Marker) {
|
|
341
|
+
try {
|
|
342
|
+
when {
|
|
343
|
+
// 网络图片
|
|
344
|
+
iconUri.startsWith("http://") || iconUri.startsWith("https://") -> {
|
|
345
|
+
loadImageFromUrl(iconUri) { bitmap ->
|
|
346
|
+
bitmap?.let {
|
|
347
|
+
val resized = resizeBitmap(it, iconWidth, iconHeight)
|
|
348
|
+
mainHandler.post {
|
|
349
|
+
marker.setIcon(BitmapDescriptorFactory.fromBitmap(resized))
|
|
350
|
+
marker.setAnchor(0.5f, 1.0f)
|
|
351
|
+
}
|
|
352
|
+
} ?: run {
|
|
353
|
+
mainHandler.post {
|
|
354
|
+
marker.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// 本地文件
|
|
360
|
+
iconUri.startsWith("file://") -> {
|
|
361
|
+
val path = iconUri.substring(7) // 移除 "file://" 前缀
|
|
362
|
+
val bitmap = BitmapFactory.decodeFile(path)
|
|
363
|
+
if (bitmap != null) {
|
|
364
|
+
val resized = resizeBitmap(bitmap, iconWidth, iconHeight)
|
|
365
|
+
marker.setIcon(BitmapDescriptorFactory.fromBitmap(resized))
|
|
366
|
+
marker.setAnchor(0.5f, 1.0f)
|
|
367
|
+
} else {
|
|
368
|
+
marker.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// 本地资源名
|
|
372
|
+
else -> {
|
|
373
|
+
val resourceId = context.resources.getIdentifier(
|
|
374
|
+
iconUri,
|
|
375
|
+
"drawable",
|
|
376
|
+
context.packageName
|
|
377
|
+
)
|
|
378
|
+
if (resourceId != 0) {
|
|
379
|
+
val bitmap = BitmapFactory.decodeResource(context.resources, resourceId)
|
|
380
|
+
val resized = resizeBitmap(bitmap, iconWidth, iconHeight)
|
|
381
|
+
marker.setIcon(BitmapDescriptorFactory.fromBitmap(resized))
|
|
382
|
+
marker.setAnchor(0.5f, 1.0f)
|
|
383
|
+
} else {
|
|
384
|
+
marker.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
} catch (e: Exception) {
|
|
389
|
+
marker.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* 从网络加载图片
|
|
395
|
+
*/
|
|
396
|
+
private fun loadImageFromUrl(url: String, callback: (Bitmap?) -> Unit) {
|
|
397
|
+
thread {
|
|
398
|
+
var connection: HttpURLConnection? = null
|
|
399
|
+
var inputStream: InputStream? = null
|
|
300
400
|
try {
|
|
301
|
-
|
|
302
|
-
|
|
401
|
+
val urlConnection = URL(url)
|
|
402
|
+
connection = urlConnection.openConnection() as HttpURLConnection
|
|
403
|
+
connection.connectTimeout = 10000
|
|
404
|
+
connection.readTimeout = 10000
|
|
405
|
+
connection.doInput = true
|
|
406
|
+
connection.connect()
|
|
407
|
+
|
|
408
|
+
if (connection.responseCode == HttpURLConnection.HTTP_OK) {
|
|
409
|
+
inputStream = connection.inputStream
|
|
410
|
+
val bitmap = BitmapFactory.decodeStream(inputStream)
|
|
411
|
+
callback(bitmap)
|
|
412
|
+
} else {
|
|
413
|
+
callback(null)
|
|
414
|
+
}
|
|
303
415
|
} catch (e: Exception) {
|
|
304
|
-
|
|
416
|
+
callback(null)
|
|
417
|
+
} finally {
|
|
418
|
+
inputStream?.close()
|
|
419
|
+
connection?.disconnect()
|
|
305
420
|
}
|
|
306
421
|
}
|
|
307
422
|
}
|
|
308
423
|
|
|
424
|
+
/**
|
|
425
|
+
* 调整图片尺寸
|
|
426
|
+
*/
|
|
427
|
+
private fun resizeBitmap(bitmap: Bitmap, width: Int, height: Int): Bitmap {
|
|
428
|
+
// 如果没有指定尺寸,使用原图尺寸或默认值
|
|
429
|
+
val finalWidth = if (width > 0) width else bitmap.width
|
|
430
|
+
val finalHeight = if (height > 0) height else bitmap.height
|
|
431
|
+
|
|
432
|
+
return if (bitmap.width == finalWidth && bitmap.height == finalHeight) {
|
|
433
|
+
bitmap
|
|
434
|
+
} else {
|
|
435
|
+
Bitmap.createScaledBitmap(bitmap, finalWidth, finalHeight, true)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* 设置大头针颜色
|
|
441
|
+
*/
|
|
442
|
+
fun setPinColor(color: String?) {
|
|
443
|
+
pendingPinColor = color
|
|
444
|
+
// 颜色变化时需要重新创建 marker
|
|
445
|
+
aMap?.let { map ->
|
|
446
|
+
marker?.let { oldMarker ->
|
|
447
|
+
val position = oldMarker.position
|
|
448
|
+
oldMarker.remove()
|
|
449
|
+
marker = null
|
|
450
|
+
|
|
451
|
+
createOrUpdateMarker()
|
|
452
|
+
marker?.position = position
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* 应用大头针颜色
|
|
459
|
+
*/
|
|
460
|
+
private fun applyPinColor(color: String, marker: Marker) {
|
|
461
|
+
try {
|
|
462
|
+
val hue = when (color.lowercase()) {
|
|
463
|
+
"red" -> BitmapDescriptorFactory.HUE_RED
|
|
464
|
+
"orange" -> BitmapDescriptorFactory.HUE_ORANGE
|
|
465
|
+
"yellow" -> BitmapDescriptorFactory.HUE_YELLOW
|
|
466
|
+
"green" -> BitmapDescriptorFactory.HUE_GREEN
|
|
467
|
+
"cyan" -> BitmapDescriptorFactory.HUE_CYAN
|
|
468
|
+
"blue" -> BitmapDescriptorFactory.HUE_BLUE
|
|
469
|
+
"violet" -> BitmapDescriptorFactory.HUE_VIOLET
|
|
470
|
+
"magenta" -> BitmapDescriptorFactory.HUE_MAGENTA
|
|
471
|
+
"rose" -> BitmapDescriptorFactory.HUE_ROSE
|
|
472
|
+
"purple" -> BitmapDescriptorFactory.HUE_VIOLET
|
|
473
|
+
else -> BitmapDescriptorFactory.HUE_RED
|
|
474
|
+
}
|
|
475
|
+
marker.setIcon(BitmapDescriptorFactory.defaultMarker(hue))
|
|
476
|
+
} catch (e: Exception) {
|
|
477
|
+
// 忽略异常
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
309
481
|
/**
|
|
310
482
|
* 设置 z-index
|
|
311
483
|
*/
|
|
312
484
|
fun setZIndex(zIndex: Float) {
|
|
485
|
+
pendingZIndex = zIndex
|
|
313
486
|
marker?.let { it.zIndex = zIndex }
|
|
314
487
|
}
|
|
315
488
|
|
|
316
489
|
/**
|
|
317
490
|
* 设置图标宽度(用于自定义图标 icon 属性)
|
|
491
|
+
* 注意:React Native 传入的是 DP 值,需要转换为 PX
|
|
318
492
|
*/
|
|
319
493
|
fun setIconWidth(width: Int) {
|
|
320
|
-
|
|
494
|
+
val density = context.resources.displayMetrics.density
|
|
495
|
+
iconWidth = (width * density).toInt()
|
|
321
496
|
}
|
|
322
497
|
|
|
323
498
|
/**
|
|
324
499
|
* 设置图标高度(用于自定义图标 icon 属性)
|
|
500
|
+
* 注意:React Native 传入的是 DP 值,需要转换为 PX
|
|
325
501
|
*/
|
|
326
502
|
fun setIconHeight(height: Int) {
|
|
327
|
-
|
|
503
|
+
val density = context.resources.displayMetrics.density
|
|
504
|
+
iconHeight = (height * density).toInt()
|
|
328
505
|
}
|
|
329
506
|
|
|
330
507
|
/**
|
|
@@ -345,6 +522,64 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
345
522
|
customViewHeight = (height * density).toInt()
|
|
346
523
|
}
|
|
347
524
|
|
|
525
|
+
/**
|
|
526
|
+
* 全局的 Marker 点击监听器
|
|
527
|
+
* 必须在 ExpoGaodeMapView 中设置,不能在每个 MarkerView 中重复设置
|
|
528
|
+
*/
|
|
529
|
+
companion object {
|
|
530
|
+
private val markerViewMap = mutableMapOf<Marker, MarkerView>()
|
|
531
|
+
|
|
532
|
+
fun registerMarker(marker: Marker, view: MarkerView) {
|
|
533
|
+
markerViewMap[marker] = view
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
fun unregisterMarker(marker: Marker) {
|
|
537
|
+
markerViewMap.remove(marker)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
fun handleMarkerClick(marker: Marker): Boolean {
|
|
541
|
+
markerViewMap[marker]?.let { view ->
|
|
542
|
+
view.onMarkerPress(mapOf(
|
|
543
|
+
"latitude" to marker.position.latitude,
|
|
544
|
+
"longitude" to marker.position.longitude
|
|
545
|
+
))
|
|
546
|
+
// 显示信息窗口(如果有 title 或 snippet)
|
|
547
|
+
if (!marker.title.isNullOrEmpty() || !marker.snippet.isNullOrEmpty()) {
|
|
548
|
+
marker.showInfoWindow()
|
|
549
|
+
}
|
|
550
|
+
return true
|
|
551
|
+
}
|
|
552
|
+
return false
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
fun handleMarkerDragStart(marker: Marker) {
|
|
556
|
+
markerViewMap[marker]?.let { view ->
|
|
557
|
+
view.onMarkerDragStart(mapOf(
|
|
558
|
+
"latitude" to marker.position.latitude,
|
|
559
|
+
"longitude" to marker.position.longitude
|
|
560
|
+
))
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
fun handleMarkerDrag(marker: Marker) {
|
|
565
|
+
markerViewMap[marker]?.let { view ->
|
|
566
|
+
view.onMarkerDrag(mapOf(
|
|
567
|
+
"latitude" to marker.position.latitude,
|
|
568
|
+
"longitude" to marker.position.longitude
|
|
569
|
+
))
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
fun handleMarkerDragEnd(marker: Marker) {
|
|
574
|
+
markerViewMap[marker]?.let { view ->
|
|
575
|
+
view.onMarkerDragEnd(mapOf(
|
|
576
|
+
"latitude" to marker.position.latitude,
|
|
577
|
+
"longitude" to marker.position.longitude
|
|
578
|
+
))
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
348
583
|
/**
|
|
349
584
|
* 创建或更新标记
|
|
350
585
|
*/
|
|
@@ -354,52 +589,28 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
354
589
|
val options = MarkerOptions()
|
|
355
590
|
marker = map.addMarker(options)
|
|
356
591
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
"latitude" to clickedMarker.position.latitude,
|
|
361
|
-
"longitude" to clickedMarker.position.longitude
|
|
362
|
-
))
|
|
363
|
-
true
|
|
364
|
-
} else {
|
|
365
|
-
false
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
map.setOnMarkerDragListener(object : AMap.OnMarkerDragListener {
|
|
370
|
-
override fun onMarkerDragStart(draggedMarker: Marker?) {
|
|
371
|
-
if (draggedMarker == marker) {
|
|
372
|
-
draggedMarker?.let {
|
|
373
|
-
onDragStart(mapOf(
|
|
374
|
-
"latitude" to it.position.latitude,
|
|
375
|
-
"longitude" to it.position.longitude
|
|
376
|
-
))
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
592
|
+
// 注册到全局 map
|
|
593
|
+
marker?.let { m ->
|
|
594
|
+
registerMarker(m, this)
|
|
380
595
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
}
|
|
596
|
+
// 应用缓存的属性
|
|
597
|
+
pendingTitle?.let { m.title = it }
|
|
598
|
+
pendingSnippet?.let { m.snippet = it }
|
|
599
|
+
pendingDraggable?.let { m.isDraggable = it }
|
|
600
|
+
pendingOpacity?.let { m.alpha = it }
|
|
601
|
+
pendingFlat?.let { m.isFlat = it }
|
|
602
|
+
pendingZIndex?.let { m.zIndex = it }
|
|
603
|
+
pendingAnchor?.let { m.setAnchor(it.first, it.second) }
|
|
391
604
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
))
|
|
399
|
-
}
|
|
605
|
+
// 优先级:children > icon > pinColor
|
|
606
|
+
if (childCount == 0) {
|
|
607
|
+
if (pendingIconUri != null) {
|
|
608
|
+
loadAndSetIcon(pendingIconUri!!, m)
|
|
609
|
+
} else if (pendingPinColor != null) {
|
|
610
|
+
applyPinColor(pendingPinColor!!, m)
|
|
400
611
|
}
|
|
401
612
|
}
|
|
402
|
-
}
|
|
613
|
+
}
|
|
403
614
|
}
|
|
404
615
|
}
|
|
405
616
|
}
|
|
@@ -468,7 +679,6 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
468
679
|
|
|
469
680
|
bitmap
|
|
470
681
|
} catch (e: Exception) {
|
|
471
|
-
android.util.Log.e("MarkerView", "创建 Bitmap 失败", e)
|
|
472
682
|
null
|
|
473
683
|
}
|
|
474
684
|
}
|
|
@@ -519,15 +729,12 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
519
729
|
try {
|
|
520
730
|
if (child != null && indexOfChild(child) >= 0) {
|
|
521
731
|
super.removeView(child)
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
marker?.setAnchor(0.5f, 1.0f)
|
|
526
|
-
}
|
|
527
|
-
}, 50)
|
|
732
|
+
// 不要在这里恢复默认图标
|
|
733
|
+
// 如果 MarkerView 整体要被移除,onDetachedFromWindow 会处理
|
|
734
|
+
// 如果只是移除 children 并保留 Marker,应该由外部重新设置 children
|
|
528
735
|
}
|
|
529
736
|
} catch (e: Exception) {
|
|
530
|
-
|
|
737
|
+
// 忽略异常
|
|
531
738
|
}
|
|
532
739
|
}
|
|
533
740
|
|
|
@@ -535,17 +742,19 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
535
742
|
try {
|
|
536
743
|
if (index >= 0 && index < childCount) {
|
|
537
744
|
super.removeViewAt(index)
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
marker
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
}
|
|
745
|
+
// 只在还有子视图时更新图标
|
|
746
|
+
if (!isRemoving && childCount > 1 && marker != null) {
|
|
747
|
+
mainHandler.postDelayed({
|
|
748
|
+
if (!isRemoving && marker != null && childCount > 0) {
|
|
749
|
+
updateMarkerIcon()
|
|
750
|
+
}
|
|
751
|
+
}, 50)
|
|
752
|
+
}
|
|
753
|
+
// 如果最后一个子视图被移除,什么都不做
|
|
754
|
+
// 让 onDetachedFromWindow 处理完整的清理
|
|
546
755
|
}
|
|
547
756
|
} catch (e: Exception) {
|
|
548
|
-
|
|
757
|
+
// 忽略异常
|
|
549
758
|
}
|
|
550
759
|
}
|
|
551
760
|
/**
|
|
@@ -569,6 +778,9 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
569
778
|
|
|
570
779
|
|
|
571
780
|
override fun addView(child: View?, index: Int, params: android.view.ViewGroup.LayoutParams?) {
|
|
781
|
+
// 🔑 关键修复:记录添加前的子视图数量
|
|
782
|
+
val childCountBefore = childCount
|
|
783
|
+
|
|
572
784
|
val finalParams = android.widget.LinearLayout.LayoutParams(
|
|
573
785
|
if (customViewWidth > 0) customViewWidth else android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
574
786
|
if (customViewHeight > 0) customViewHeight else android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
|
|
@@ -587,20 +799,31 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
587
799
|
fixChildLayoutParams(it)
|
|
588
800
|
}
|
|
589
801
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
802
|
+
// 🔑 关键修复:只有在子视图数量真正变化且 marker 已存在时才更新图标
|
|
803
|
+
// 避免在其他覆盖物添加时触发不必要的刷新
|
|
804
|
+
if (!isRemoving && marker != null && childCount > childCountBefore) {
|
|
805
|
+
mainHandler.postDelayed({
|
|
806
|
+
if (!isRemoving && marker != null) {
|
|
807
|
+
updateMarkerIcon()
|
|
808
|
+
}
|
|
809
|
+
}, 50)
|
|
810
|
+
|
|
811
|
+
mainHandler.postDelayed({
|
|
812
|
+
if (!isRemoving && marker != null) {
|
|
813
|
+
updateMarkerIcon()
|
|
814
|
+
}
|
|
815
|
+
}, 150)
|
|
816
|
+
}
|
|
597
817
|
}
|
|
598
818
|
|
|
599
819
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
600
820
|
super.onLayout(changed, left, top, right, bottom)
|
|
601
|
-
|
|
821
|
+
// 🔑 关键修复:只有在有子视图且 marker 存在时才更新,避免不必要的刷新
|
|
822
|
+
if (changed && !isRemoving && childCount > 0 && marker != null) {
|
|
602
823
|
mainHandler.postDelayed({
|
|
603
|
-
if (marker != null)
|
|
824
|
+
if (!isRemoving && marker != null) {
|
|
825
|
+
updateMarkerIcon()
|
|
826
|
+
}
|
|
604
827
|
}, 200)
|
|
605
828
|
}
|
|
606
829
|
}
|
|
@@ -609,13 +832,19 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
609
832
|
* 移除标记
|
|
610
833
|
*/
|
|
611
834
|
fun removeMarker() {
|
|
612
|
-
marker?.
|
|
835
|
+
marker?.let {
|
|
836
|
+
unregisterMarker(it)
|
|
837
|
+
it.remove()
|
|
838
|
+
}
|
|
613
839
|
marker = null
|
|
614
840
|
}
|
|
615
841
|
|
|
616
842
|
override fun onDetachedFromWindow() {
|
|
617
843
|
super.onDetachedFromWindow()
|
|
618
844
|
|
|
845
|
+
// 标记正在移除
|
|
846
|
+
isRemoving = true
|
|
847
|
+
|
|
619
848
|
// 清理所有延迟任务
|
|
620
849
|
mainHandler.removeCallbacksAndMessages(null)
|
|
621
850
|
|
|
@@ -11,7 +11,7 @@ class MarkerViewModule : Module() {
|
|
|
11
11
|
Name("MarkerView")
|
|
12
12
|
|
|
13
13
|
View(MarkerView::class) {
|
|
14
|
-
Events("
|
|
14
|
+
Events("onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd")
|
|
15
15
|
|
|
16
16
|
// 拆分 position 为两个独立属性以兼容 React Native 旧架构
|
|
17
17
|
Prop<Double>("latitude") { view, lat ->
|
|
@@ -26,14 +26,22 @@ class MarkerViewModule : Module() {
|
|
|
26
26
|
view.setTitle(title)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
Prop<String>("
|
|
30
|
-
view.setDescription(
|
|
29
|
+
Prop<String>("snippet") { view, snippet ->
|
|
30
|
+
view.setDescription(snippet)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
Prop<Boolean>("draggable") { view, draggable ->
|
|
34
34
|
view.setDraggable(draggable)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
Prop<String>("icon") { view, icon ->
|
|
38
|
+
view.setMarkerIcon(icon)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Prop<String>("pinColor") { view, color ->
|
|
42
|
+
view.setPinColor(color)
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
Prop<Float>("opacity") { view, opacity ->
|
|
38
46
|
view.setOpacity(opacity)
|
|
39
47
|
}
|
|
@@ -38,7 +38,8 @@ class MultiPointView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
38
38
|
val lng = (point["longitude"] as? Number)?.toDouble()
|
|
39
39
|
val id = point["id"] as? String ?: ""
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
// 坐标验证
|
|
42
|
+
if (lat != null && lng != null && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
|
|
42
43
|
val multiPointItem = MultiPointItem(LatLng(lat, lng))
|
|
43
44
|
multiPointItem.customerId = id
|
|
44
45
|
points.add(multiPointItem)
|
|
@@ -94,10 +95,12 @@ class MultiPointView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
94
95
|
fun removeMultiPoint() {
|
|
95
96
|
multiPointOverlay?.remove()
|
|
96
97
|
multiPointOverlay = null
|
|
98
|
+
points.clear()
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
override fun onDetachedFromWindow() {
|
|
100
102
|
super.onDetachedFromWindow()
|
|
101
103
|
removeMultiPoint()
|
|
104
|
+
aMap = null
|
|
102
105
|
}
|
|
103
106
|
}
|