expo-gaode-map 2.2.30-next.0 → 2.2.30
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/ExpoGaodeMapModule.kt +4 -2
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +117 -57
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +8 -15
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +20 -6
- package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +24 -13
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerBitmapRenderer.kt +351 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +94 -310
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +3 -3
- package/build/ExpoGaodeMapModule.d.ts +13 -5
- package/build/ExpoGaodeMapModule.d.ts.map +1 -1
- package/build/ExpoGaodeMapModule.js +166 -34
- package/build/ExpoGaodeMapModule.js.map +1 -1
- package/build/ExpoGaodeMapView.d.ts.map +1 -1
- package/build/ExpoGaodeMapView.js +12 -0
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/AreaMaskOverlay.d.ts +5 -0
- package/build/components/AreaMaskOverlay.d.ts.map +1 -0
- package/build/components/AreaMaskOverlay.js +20 -0
- package/build/components/AreaMaskOverlay.js.map +1 -0
- package/build/components/FoldableMapView.d.ts.map +1 -1
- package/build/components/FoldableMapView.js +115 -104
- package/build/components/FoldableMapView.js.map +1 -1
- package/build/components/RouteOverlay.d.ts +5 -0
- package/build/components/RouteOverlay.d.ts.map +1 -0
- package/build/components/RouteOverlay.js +20 -0
- package/build/components/RouteOverlay.js.map +1 -0
- package/build/components/overlays/Cluster.d.ts.map +1 -1
- package/build/components/overlays/Cluster.js +12 -0
- package/build/components/overlays/Cluster.js.map +1 -1
- package/build/components/overlays/Marker.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +86 -3
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/hooks/useRoutePlayback.d.ts +4 -0
- package/build/hooks/useRoutePlayback.d.ts.map +1 -0
- package/build/hooks/useRoutePlayback.js +310 -0
- package/build/hooks/useRoutePlayback.js.map +1 -0
- package/build/index.d.ts +4 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/types/common.types.d.ts +29 -5
- package/build/types/common.types.d.ts.map +1 -1
- package/build/types/common.types.js +5 -5
- package/build/types/common.types.js.map +1 -1
- package/build/types/index.d.ts +3 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js.map +1 -1
- package/build/types/location.types.d.ts +28 -0
- package/build/types/location.types.d.ts.map +1 -1
- package/build/types/location.types.js +5 -0
- package/build/types/location.types.js.map +1 -1
- package/build/types/map-view.types.d.ts +22 -22
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/types/native-module.types.d.ts +2 -2
- package/build/types/native-module.types.d.ts.map +1 -1
- package/build/types/native-module.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +14 -0
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/build/types/route-playback.types.d.ts +118 -0
- package/build/types/route-playback.types.d.ts.map +1 -0
- package/build/types/route-playback.types.js +2 -0
- package/build/types/route-playback.types.js.map +1 -0
- package/build/utils/RouteUtils.d.ts +8 -0
- package/build/utils/RouteUtils.d.ts.map +1 -0
- package/build/utils/RouteUtils.js +140 -0
- package/build/utils/RouteUtils.js.map +1 -0
- package/ios/ExpoGaodeMapModule.swift +41 -22
- package/ios/ExpoGaodeMapView.swift +236 -241
- package/ios/ExpoGaodeMapViewModule.swift +16 -11
- package/ios/managers/UIManager.swift +5 -4
- package/ios/modules/LocationManager.swift +32 -9
- package/ios/overlays/ClusterView.swift +114 -12
- package/ios/overlays/ClusterViewModule.swift +5 -1
- package/ios/overlays/MarkerView.swift +195 -18
- package/ios/overlays/MarkerViewModule.swift +7 -7
- package/package.json +6 -6
- package/build/utils/throttle.d.ts +0 -10
- package/build/utils/throttle.d.ts.map +0 -1
- package/build/utils/throttle.js +0 -19
- package/build/utils/throttle.js.map +0 -1
|
@@ -772,7 +772,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
772
772
|
// 使用 WeakReference 避免内存泄露
|
|
773
773
|
val contextRef = java.lang.ref.WeakReference(appContext.reactContext)
|
|
774
774
|
val handler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
775
|
-
|
|
775
|
+
var attempts = 0
|
|
776
776
|
val maxAttempts = 50 // 增加到 5 秒 / 100ms,给用户足够时间操作
|
|
777
777
|
|
|
778
778
|
val checkPermission = object : Runnable {
|
|
@@ -784,6 +784,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
784
784
|
}
|
|
785
785
|
|
|
786
786
|
val status = PermissionHelper.checkForegroundLocationPermission(context)
|
|
787
|
+
attempts += 1
|
|
787
788
|
|
|
788
789
|
// 如果权限已授予或达到最大尝试次数,返回结果并清理 Handler
|
|
789
790
|
if (status.granted || attempts >= maxAttempts) {
|
|
@@ -843,7 +844,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
843
844
|
// 轮询检查权限状态
|
|
844
845
|
val contextRef = java.lang.ref.WeakReference(appContext.reactContext)
|
|
845
846
|
val handler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
846
|
-
|
|
847
|
+
var attempts = 0
|
|
847
848
|
val maxAttempts = 30
|
|
848
849
|
|
|
849
850
|
val checkPermission = object : Runnable {
|
|
@@ -855,6 +856,7 @@ class ExpoGaodeMapModule : Module() {
|
|
|
855
856
|
}
|
|
856
857
|
|
|
857
858
|
val status = PermissionHelper.checkBackgroundLocationPermission(context)
|
|
859
|
+
attempts += 1
|
|
858
860
|
|
|
859
861
|
if (status.granted || attempts >= maxAttempts) {
|
|
860
862
|
handler.removeCallbacks(this)
|
|
@@ -2,6 +2,7 @@ package expo.modules.gaodemap
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.os.SystemClock
|
|
5
6
|
import android.view.View
|
|
6
7
|
import android.view.ViewGroup
|
|
7
8
|
import com.amap.api.maps.AMap
|
|
@@ -107,11 +108,17 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
107
108
|
|
|
108
109
|
// Props 存储
|
|
109
110
|
/** 地图类型 */
|
|
110
|
-
internal var mapType: Int =
|
|
111
|
+
internal var mapType: Int = 1
|
|
111
112
|
/** 初始相机位置 */
|
|
112
113
|
internal var initialCameraPosition: Map<String, Any?>? = null
|
|
113
114
|
/** 是否跟随用户位置 */
|
|
114
115
|
internal var followUserLocation: Boolean = false
|
|
116
|
+
/** 是否显示底图文字标注 */
|
|
117
|
+
private var labelsEnabled: Boolean = true
|
|
118
|
+
/** 是否显示定位按钮 */
|
|
119
|
+
private var myLocationButtonEnabled: Boolean = false
|
|
120
|
+
/** 相机移动事件节流间隔 */
|
|
121
|
+
private var cameraEventThrottleMs: Long = 32L
|
|
115
122
|
/** 自定义地图样式配置(缓存) */
|
|
116
123
|
private var customMapStyleData: Map<String, Any>? = null
|
|
117
124
|
|
|
@@ -120,6 +127,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
120
127
|
|
|
121
128
|
// 事件派发器
|
|
122
129
|
private val onMapPress by EventDispatcher()
|
|
130
|
+
private val onPressPoi by EventDispatcher()
|
|
123
131
|
private val onMapLongPress by EventDispatcher()
|
|
124
132
|
private val onLoad by EventDispatcher()
|
|
125
133
|
private val onLocation by EventDispatcher()
|
|
@@ -128,6 +136,8 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
128
136
|
|
|
129
137
|
// 缓存的相机移动事件数据
|
|
130
138
|
private var pendingCameraMoveData: Map<String, Any>? = null
|
|
139
|
+
private var pendingCameraMoveDispatch: Runnable? = null
|
|
140
|
+
private var lastCameraMoveDispatchAt: Long = 0L
|
|
131
141
|
|
|
132
142
|
// 高德地图视图
|
|
133
143
|
private lateinit var mapView: TextureMapView
|
|
@@ -176,7 +186,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
176
186
|
isMapLoaded = true
|
|
177
187
|
|
|
178
188
|
// 应用缓存的 Props
|
|
179
|
-
if (mapType !=
|
|
189
|
+
if (mapType != 1) {
|
|
180
190
|
setMapType(mapType)
|
|
181
191
|
}
|
|
182
192
|
|
|
@@ -191,6 +201,9 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
191
201
|
uiManager.setCustomMapStyle(styleData)
|
|
192
202
|
}
|
|
193
203
|
|
|
204
|
+
uiManager.setLabelsEnabled(labelsEnabled)
|
|
205
|
+
uiManager.setMyLocationButtonEnabled(myLocationButtonEnabled)
|
|
206
|
+
|
|
194
207
|
onLoad(mapOf("loaded" to true))
|
|
195
208
|
}
|
|
196
209
|
} catch (_: Exception) {
|
|
@@ -223,39 +236,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
223
236
|
|
|
224
237
|
// 相机移动中 - 应用节流优化
|
|
225
238
|
cameraPosition?.let {
|
|
226
|
-
|
|
227
|
-
val eventData = mapOf(
|
|
228
|
-
"cameraPosition" to mapOf(
|
|
229
|
-
"target" to mapOf(
|
|
230
|
-
"latitude" to it.target.latitude,
|
|
231
|
-
"longitude" to it.target.longitude
|
|
232
|
-
),
|
|
233
|
-
"zoom" to it.zoom,
|
|
234
|
-
"tilt" to it.tilt,
|
|
235
|
-
"bearing" to it.bearing
|
|
236
|
-
),
|
|
237
|
-
"latLngBounds" to mapOf(
|
|
238
|
-
"northeast" to mapOf(
|
|
239
|
-
"latitude" to visibleRegion.farRight.latitude,
|
|
240
|
-
"longitude" to visibleRegion.farRight.longitude
|
|
241
|
-
),
|
|
242
|
-
"southwest" to mapOf(
|
|
243
|
-
"latitude" to visibleRegion.nearLeft.latitude,
|
|
244
|
-
"longitude" to visibleRegion.nearLeft.longitude
|
|
245
|
-
)
|
|
246
|
-
)
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
// 使用 onCameraMove 自身的节流机制(如果在 Module 定义中配置了 Coalescing)
|
|
250
|
-
// 或者在这里简单发送,让 JS 端处理节流,或者依赖 Expo 的事件批处理
|
|
251
|
-
// 这里我们移除自定义的 Handler 实现,直接发送事件,简化代码逻辑
|
|
252
|
-
// 注意:高德地图的 onCameraChange 调用频率非常高,
|
|
253
|
-
// 建议在 Module 定义中使用 Events("onCameraMove") 时考虑是否需要原生侧节流
|
|
254
|
-
// 目前 Expo Modules 默认没有自动节流,但为了代码简洁和避免 Handler 泄漏风险,
|
|
255
|
-
// 我们可以依赖 JS 端的 debounce/throttle,或者如果性能是瓶颈,再加回轻量级的节流。
|
|
256
|
-
// 鉴于之前的 Handler 实现比较复杂且容易出错,我们先简化。
|
|
257
|
-
|
|
258
|
-
onCameraMove(eventData)
|
|
239
|
+
dispatchCameraMoveEvent(buildCameraEventData(it))
|
|
259
240
|
}
|
|
260
241
|
}
|
|
261
242
|
|
|
@@ -265,28 +246,8 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
265
246
|
|
|
266
247
|
// 相机移动完成
|
|
267
248
|
cameraPosition?.let {
|
|
268
|
-
|
|
269
|
-
onCameraIdle(
|
|
270
|
-
"cameraPosition" to mapOf(
|
|
271
|
-
"target" to mapOf(
|
|
272
|
-
"latitude" to it.target.latitude,
|
|
273
|
-
"longitude" to it.target.longitude
|
|
274
|
-
),
|
|
275
|
-
"zoom" to it.zoom,
|
|
276
|
-
"tilt" to it.tilt,
|
|
277
|
-
"bearing" to it.bearing
|
|
278
|
-
),
|
|
279
|
-
"latLngBounds" to mapOf(
|
|
280
|
-
"northeast" to mapOf(
|
|
281
|
-
"latitude" to visibleRegion.farRight.latitude,
|
|
282
|
-
"longitude" to visibleRegion.farRight.longitude
|
|
283
|
-
),
|
|
284
|
-
"southwest" to mapOf(
|
|
285
|
-
"latitude" to visibleRegion.nearLeft.latitude,
|
|
286
|
-
"longitude" to visibleRegion.nearLeft.longitude
|
|
287
|
-
)
|
|
288
|
-
)
|
|
289
|
-
))
|
|
249
|
+
flushPendingCameraMoveEvent()
|
|
250
|
+
onCameraIdle(buildCameraEventData(it))
|
|
290
251
|
}
|
|
291
252
|
}
|
|
292
253
|
})
|
|
@@ -353,6 +314,17 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
353
314
|
))
|
|
354
315
|
}
|
|
355
316
|
|
|
317
|
+
aMap.setOnPOIClickListener { poi ->
|
|
318
|
+
onPressPoi(mapOf(
|
|
319
|
+
"id" to poi.poiId,
|
|
320
|
+
"name" to poi.name,
|
|
321
|
+
"position" to mapOf(
|
|
322
|
+
"latitude" to poi.coordinate.latitude,
|
|
323
|
+
"longitude" to poi.coordinate.longitude
|
|
324
|
+
)
|
|
325
|
+
))
|
|
326
|
+
}
|
|
327
|
+
|
|
356
328
|
aMap.setOnMapLongClickListener { latLng ->
|
|
357
329
|
onMapLongPress(mapOf(
|
|
358
330
|
"latitude" to latLng.latitude,
|
|
@@ -456,6 +428,24 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
456
428
|
fun setShowsBuildings(show: Boolean) = uiManager.setShowsBuildings(show)
|
|
457
429
|
/** 设置是否显示室内地图 */
|
|
458
430
|
fun setShowsIndoorMap(show: Boolean) = uiManager.setShowsIndoorMap(show)
|
|
431
|
+
/** 设置是否显示底图文字标注 */
|
|
432
|
+
fun setLabelsEnabled(enabled: Boolean) {
|
|
433
|
+
labelsEnabled = enabled
|
|
434
|
+
uiManager.setLabelsEnabled(enabled)
|
|
435
|
+
}
|
|
436
|
+
/** 设置是否显示定位按钮 */
|
|
437
|
+
fun setMyLocationButtonEnabled(enabled: Boolean) {
|
|
438
|
+
myLocationButtonEnabled = enabled
|
|
439
|
+
uiManager.setMyLocationButtonEnabled(enabled)
|
|
440
|
+
}
|
|
441
|
+
/** 设置相机移动事件节流间隔 */
|
|
442
|
+
fun setCameraEventThrottleMs(throttleMs: Int) {
|
|
443
|
+
cameraEventThrottleMs = throttleMs.toLong().coerceAtLeast(0L)
|
|
444
|
+
if (cameraEventThrottleMs == 0L) {
|
|
445
|
+
pendingCameraMoveDispatch?.let(mainHandler::removeCallbacks)
|
|
446
|
+
pendingCameraMoveDispatch = null
|
|
447
|
+
}
|
|
448
|
+
}
|
|
459
449
|
|
|
460
450
|
/**
|
|
461
451
|
* 设置自定义地图样式
|
|
@@ -641,9 +631,12 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
641
631
|
try {
|
|
642
632
|
// 清理 Handler 回调,防止内存泄露
|
|
643
633
|
mainHandler.removeCallbacksAndMessages(null)
|
|
634
|
+
pendingCameraMoveData = null
|
|
635
|
+
pendingCameraMoveDispatch = null
|
|
644
636
|
|
|
645
637
|
// 清理所有地图监听器
|
|
646
638
|
aMap.setOnMapClickListener(null)
|
|
639
|
+
aMap.setOnPOIClickListener(null)
|
|
647
640
|
aMap.setOnMapLongClickListener(null)
|
|
648
641
|
aMap.setOnMapLoadedListener(null)
|
|
649
642
|
aMap.setOnCameraChangeListener(null)
|
|
@@ -663,6 +656,73 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
663
656
|
|
|
664
657
|
}
|
|
665
658
|
|
|
659
|
+
private fun buildCameraEventData(cameraPosition: com.amap.api.maps.model.CameraPosition): Map<String, Any> {
|
|
660
|
+
val visibleRegion = aMap.projection.visibleRegion
|
|
661
|
+
return mapOf(
|
|
662
|
+
"cameraPosition" to mapOf(
|
|
663
|
+
"target" to mapOf(
|
|
664
|
+
"latitude" to cameraPosition.target.latitude,
|
|
665
|
+
"longitude" to cameraPosition.target.longitude
|
|
666
|
+
),
|
|
667
|
+
"zoom" to cameraPosition.zoom,
|
|
668
|
+
"tilt" to cameraPosition.tilt,
|
|
669
|
+
"bearing" to cameraPosition.bearing
|
|
670
|
+
),
|
|
671
|
+
"latLngBounds" to mapOf(
|
|
672
|
+
"northeast" to mapOf(
|
|
673
|
+
"latitude" to visibleRegion.farRight.latitude,
|
|
674
|
+
"longitude" to visibleRegion.farRight.longitude
|
|
675
|
+
),
|
|
676
|
+
"southwest" to mapOf(
|
|
677
|
+
"latitude" to visibleRegion.nearLeft.latitude,
|
|
678
|
+
"longitude" to visibleRegion.nearLeft.longitude
|
|
679
|
+
)
|
|
680
|
+
)
|
|
681
|
+
)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
private fun dispatchCameraMoveEvent(eventData: Map<String, Any>) {
|
|
685
|
+
val throttleMs = cameraEventThrottleMs.coerceAtLeast(0L)
|
|
686
|
+
if (throttleMs == 0L) {
|
|
687
|
+
pendingCameraMoveData = null
|
|
688
|
+
pendingCameraMoveDispatch?.let(mainHandler::removeCallbacks)
|
|
689
|
+
pendingCameraMoveDispatch = null
|
|
690
|
+
lastCameraMoveDispatchAt = SystemClock.uptimeMillis()
|
|
691
|
+
onCameraMove(eventData)
|
|
692
|
+
return
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
pendingCameraMoveData = eventData
|
|
696
|
+
|
|
697
|
+
val now = SystemClock.uptimeMillis()
|
|
698
|
+
val elapsed = now - lastCameraMoveDispatchAt
|
|
699
|
+
if (elapsed >= throttleMs) {
|
|
700
|
+
pendingCameraMoveDispatch?.let(mainHandler::removeCallbacks)
|
|
701
|
+
pendingCameraMoveDispatch = null
|
|
702
|
+
flushPendingCameraMoveEvent(now)
|
|
703
|
+
return
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (pendingCameraMoveDispatch != null) {
|
|
707
|
+
return
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
val delay = (throttleMs - elapsed).coerceAtLeast(0L)
|
|
711
|
+
val runnable = Runnable {
|
|
712
|
+
pendingCameraMoveDispatch = null
|
|
713
|
+
flushPendingCameraMoveEvent()
|
|
714
|
+
}
|
|
715
|
+
pendingCameraMoveDispatch = runnable
|
|
716
|
+
mainHandler.postDelayed(runnable, delay)
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
private fun flushPendingCameraMoveEvent(timestamp: Long = SystemClock.uptimeMillis()) {
|
|
720
|
+
val eventData = pendingCameraMoveData ?: return
|
|
721
|
+
pendingCameraMoveData = null
|
|
722
|
+
lastCameraMoveDispatchAt = timestamp
|
|
723
|
+
onCameraMove(eventData)
|
|
724
|
+
}
|
|
725
|
+
|
|
666
726
|
/** 保存实例状态 */
|
|
667
727
|
@Suppress("unused")
|
|
668
728
|
fun onSaveInstanceState(outState: android.os.Bundle) {
|
|
@@ -3,16 +3,6 @@ package expo.modules.gaodemap
|
|
|
3
3
|
import expo.modules.kotlin.modules.Module
|
|
4
4
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
5
|
|
|
6
|
-
import expo.modules.kotlin.types.Enumerable
|
|
7
|
-
|
|
8
|
-
enum class MapType(val value: Int) : Enumerable {
|
|
9
|
-
STANDARD(1),
|
|
10
|
-
SATELLITE(2),
|
|
11
|
-
NIGHT(3),
|
|
12
|
-
NAVI(4),
|
|
13
|
-
BUS(5)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
6
|
/**
|
|
17
7
|
* 高德地图视图 Module
|
|
18
8
|
*/
|
|
@@ -21,7 +11,7 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
21
11
|
Name("ExpoGaodeMapView")
|
|
22
12
|
|
|
23
13
|
View(ExpoGaodeMapView::class) {
|
|
24
|
-
Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onCameraMove", "onCameraIdle")
|
|
14
|
+
Events("onMapPress", "onPressPoi", "onMapLongPress", "onLoad", "onLocation", "onCameraMove", "onCameraIdle")
|
|
25
15
|
|
|
26
16
|
|
|
27
17
|
|
|
@@ -34,9 +24,9 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
34
24
|
}
|
|
35
25
|
|
|
36
26
|
|
|
37
|
-
Prop<
|
|
38
|
-
view.mapType = type
|
|
39
|
-
view.setMapType(type
|
|
27
|
+
Prop<Int>("mapType") { view, type ->
|
|
28
|
+
view.mapType = type
|
|
29
|
+
view.setMapType(type)
|
|
40
30
|
}
|
|
41
31
|
|
|
42
32
|
Prop<Map<String, Any?>?>("initialCameraPosition") { view, position ->
|
|
@@ -64,13 +54,16 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
64
54
|
Prop<Boolean>("trafficEnabled") { view, show -> view.setShowsTraffic(show) }
|
|
65
55
|
Prop<Boolean>("buildingsEnabled") { view, show -> view.setShowsBuildings(show) }
|
|
66
56
|
Prop<Boolean>("indoorViewEnabled") { view, show -> view.setShowsIndoorMap(show) }
|
|
57
|
+
Prop<Boolean>("labelsEnabled") { view, enabled -> view.setLabelsEnabled(enabled) }
|
|
58
|
+
Prop<Boolean>("myLocationButtonEnabled") { view, enabled -> view.setMyLocationButtonEnabled(enabled) }
|
|
59
|
+
Prop<Int>("cameraEventThrottleMs") { view, throttleMs -> view.setCameraEventThrottleMs(throttleMs) }
|
|
67
60
|
|
|
68
61
|
Prop<Map<String, Any>?>("customMapStyle") { view, styleData ->
|
|
69
62
|
styleData?.let { view.setCustomMapStyle(it) }
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
OnViewDidUpdateProps { view: ExpoGaodeMapView ->
|
|
73
|
-
if (view.mapType !=
|
|
66
|
+
if (view.mapType != 1) {
|
|
74
67
|
view.setMapType(view.mapType)
|
|
75
68
|
}
|
|
76
69
|
|
|
@@ -46,6 +46,13 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
46
46
|
fun setShowsScale(show: Boolean) {
|
|
47
47
|
aMap.uiSettings.isScaleControlsEnabled = show
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 设置是否显示定位按钮
|
|
52
|
+
*/
|
|
53
|
+
fun setMyLocationButtonEnabled(enabled: Boolean) {
|
|
54
|
+
aMap.uiSettings.isMyLocationButtonEnabled = enabled
|
|
55
|
+
}
|
|
49
56
|
|
|
50
57
|
// ==================== 手势控制 ====================
|
|
51
58
|
|
|
@@ -322,7 +329,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
322
329
|
fun setShowsTraffic(show: Boolean) {
|
|
323
330
|
aMap.isTrafficEnabled = show
|
|
324
331
|
}
|
|
325
|
-
|
|
332
|
+
|
|
326
333
|
/**
|
|
327
334
|
* 设置是否显示建筑物
|
|
328
335
|
*/
|
|
@@ -336,17 +343,24 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
336
343
|
fun setShowsIndoorMap(show: Boolean) {
|
|
337
344
|
aMap.showIndoorMap(show)
|
|
338
345
|
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* 设置是否显示底图文字标注
|
|
349
|
+
*/
|
|
350
|
+
fun setLabelsEnabled(enabled: Boolean) {
|
|
351
|
+
aMap.showMapText(enabled)
|
|
352
|
+
}
|
|
339
353
|
|
|
340
354
|
/**
|
|
341
355
|
* 设置地图类型
|
|
342
356
|
*/
|
|
343
357
|
fun setMapType(type: Int) {
|
|
344
358
|
aMap.mapType = when (type) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
else -> AMap.MAP_TYPE_NORMAL // 标准地图
|
|
359
|
+
2 -> AMap.MAP_TYPE_SATELLITE // 卫星地图
|
|
360
|
+
3 -> AMap.MAP_TYPE_NIGHT // 夜间地图
|
|
361
|
+
4 -> AMap.MAP_TYPE_NAVI // 导航地图
|
|
362
|
+
5 -> AMap.MAP_TYPE_BUS // 公交地图
|
|
363
|
+
else -> AMap.MAP_TYPE_NORMAL // 标准地图 (1, 以及兼容旧值 0)
|
|
350
364
|
}
|
|
351
365
|
}
|
|
352
366
|
|
|
@@ -2,7 +2,6 @@ package expo.modules.gaodemap.overlays
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
-
import android.util.Log
|
|
6
5
|
import android.graphics.Bitmap
|
|
7
6
|
import android.graphics.BitmapFactory
|
|
8
7
|
import android.graphics.Canvas
|
|
@@ -64,7 +63,6 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
64
63
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
private var rawPoints: List<Map<String, Any>> = emptyList()
|
|
68
66
|
private var clusterItems: List<ClusterItem> = emptyList()
|
|
69
67
|
private var clusters: List<Cluster> = emptyList()
|
|
70
68
|
|
|
@@ -91,6 +89,7 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
91
89
|
private var currentIconDescriptor: BitmapDescriptor? = null
|
|
92
90
|
private var customIconBitmap: Bitmap? = null
|
|
93
91
|
private var pendingIconUri: String? = null
|
|
92
|
+
private var pendingRetryUpdate: Runnable? = null
|
|
94
93
|
|
|
95
94
|
// 标记样式是否发生变化,用于强制更新图标
|
|
96
95
|
private var styleChanged = false
|
|
@@ -117,7 +116,6 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
117
116
|
* 设置聚合点
|
|
118
117
|
*/
|
|
119
118
|
fun setPoints(points: List<Map<String, Any>>) {
|
|
120
|
-
rawPoints = points
|
|
121
119
|
clusterItems = points.mapNotNull { pointData ->
|
|
122
120
|
LatLngParser.parseLatLng(pointData)?.let { latLng ->
|
|
123
121
|
ClusterItem(latLng, pointData)
|
|
@@ -141,7 +139,6 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
141
139
|
* 设置最小聚合数量
|
|
142
140
|
*/
|
|
143
141
|
fun setMinClusterSize(size: Int) {
|
|
144
|
-
Log.d("ClusterView", "setMinClusterSize: $size")
|
|
145
142
|
minClusterSize = size
|
|
146
143
|
updateClusters()
|
|
147
144
|
}
|
|
@@ -227,8 +224,8 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
227
224
|
updateClusters()
|
|
228
225
|
}
|
|
229
226
|
}
|
|
230
|
-
} catch (
|
|
231
|
-
|
|
227
|
+
} catch (_: Exception) {
|
|
228
|
+
// 忽略异常,保留当前默认图标
|
|
232
229
|
}
|
|
233
230
|
}
|
|
234
231
|
}
|
|
@@ -265,6 +262,8 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
265
262
|
}
|
|
266
263
|
currentMarkers.clear()
|
|
267
264
|
bitmapCache.clear()
|
|
265
|
+
pendingRetryUpdate?.let { mainHandler.removeCallbacks(it) }
|
|
266
|
+
pendingRetryUpdate = null
|
|
268
267
|
}
|
|
269
268
|
|
|
270
269
|
/**
|
|
@@ -283,7 +282,12 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
283
282
|
}
|
|
284
283
|
|
|
285
284
|
calculationJob = scope.launch(Dispatchers.Default) {
|
|
286
|
-
if (clusterItems.isEmpty())
|
|
285
|
+
if (clusterItems.isEmpty()) {
|
|
286
|
+
withContext(Dispatchers.Main) {
|
|
287
|
+
renderClusters(emptyList())
|
|
288
|
+
}
|
|
289
|
+
return@launch
|
|
290
|
+
}
|
|
287
291
|
|
|
288
292
|
// 获取当前比例尺 (米/像素)
|
|
289
293
|
val scalePerPixel = withContext(Dispatchers.Main) {
|
|
@@ -296,11 +300,7 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
296
300
|
}
|
|
297
301
|
|
|
298
302
|
if (scalePerPixel <= 0) {
|
|
299
|
-
|
|
300
|
-
withContext(Dispatchers.Main) {
|
|
301
|
-
Log.w("ClusterView", "Invalid scalePerPixel: $scalePerPixel, retrying...")
|
|
302
|
-
mainHandler.postDelayed({ updateClusters() }, 500)
|
|
303
|
-
}
|
|
303
|
+
scheduleRetryUpdate()
|
|
304
304
|
return@launch
|
|
305
305
|
}
|
|
306
306
|
|
|
@@ -319,6 +319,18 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
+
private fun scheduleRetryUpdate(delayMs: Long = 500L) {
|
|
323
|
+
pendingRetryUpdate?.let { mainHandler.removeCallbacks(it) }
|
|
324
|
+
val retryTask = Runnable {
|
|
325
|
+
pendingRetryUpdate = null
|
|
326
|
+
if (aMap != null) {
|
|
327
|
+
updateClusters()
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
pendingRetryUpdate = retryTask
|
|
331
|
+
mainHandler.postDelayed(retryTask, delayMs)
|
|
332
|
+
}
|
|
333
|
+
|
|
322
334
|
private fun buildClustersFromNative(radiusMeters: Double): List<Cluster>? {
|
|
323
335
|
return try {
|
|
324
336
|
val latitudes = DoubleArray(clusterItems.size)
|
|
@@ -396,7 +408,6 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
|
|
|
396
408
|
* 使用 Diff 算法优化渲染,避免全量刷新导致的闪烁
|
|
397
409
|
*/
|
|
398
410
|
private fun renderClusters(newClusters: List<Cluster>) {
|
|
399
|
-
Log.d("ClusterView", "renderClusters: count=${newClusters.size}, minClusterSize=$minClusterSize")
|
|
400
411
|
val map = aMap ?: return
|
|
401
412
|
clusters = newClusters
|
|
402
413
|
|