expo-gaode-map-navigation 1.1.5-next.1 → 1.1.5-next.2
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/build.gradle +10 -0
- package/android/src/main/cpp/CMakeLists.txt +24 -0
- package/android/src/main/cpp/cluster_jni.cpp +848 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
- package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
- package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
- package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
- package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
- package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
- package/build/ExpoGaodeMapNaviView.d.ts +7 -7
- package/build/ExpoGaodeMapNaviView.js +8 -8
- package/build/index.d.ts +1 -1
- package/build/index.js +2 -2
- package/build/map/ExpoGaodeMapModule.d.ts +2 -201
- package/build/map/ExpoGaodeMapModule.js +584 -14
- package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
- package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
- package/build/map/ExpoGaodeMapView.js +66 -58
- package/build/map/components/FoldableMapView.d.ts +38 -0
- package/build/map/components/FoldableMapView.js +209 -0
- package/build/map/components/MapContext.d.ts +12 -0
- package/build/map/components/MapContext.js +54 -0
- package/build/map/components/MapUI.d.ts +18 -0
- package/build/map/components/MapUI.js +29 -0
- package/build/map/components/overlays/Circle.js +34 -3
- package/build/map/components/overlays/Cluster.d.ts +3 -1
- package/build/map/components/overlays/Cluster.js +31 -2
- package/build/map/components/overlays/HeatMap.d.ts +3 -1
- package/build/map/components/overlays/HeatMap.js +33 -3
- package/build/map/components/overlays/Marker.d.ts +1 -1
- package/build/map/components/overlays/Marker.js +37 -32
- package/build/map/components/overlays/MultiPoint.js +1 -1
- package/build/map/components/overlays/Polygon.js +30 -3
- package/build/map/components/overlays/Polyline.js +36 -3
- package/build/map/index.d.ts +25 -5
- package/build/map/index.js +59 -18
- package/build/map/types/common.types.d.ts +40 -0
- package/build/map/types/common.types.js +0 -4
- package/build/map/types/index.d.ts +3 -2
- package/build/map/types/map-view.types.d.ts +108 -3
- package/build/map/types/native-module.types.d.ts +363 -0
- package/build/map/types/native-module.types.js +5 -0
- package/build/map/types/offline.types.d.ts +132 -0
- package/build/map/types/offline.types.js +5 -0
- package/build/map/types/overlays.types.d.ts +137 -24
- package/build/map/utils/ErrorHandler.d.ts +110 -0
- package/build/map/utils/ErrorHandler.js +421 -0
- package/build/map/utils/GeoUtils.d.ts +20 -0
- package/build/map/utils/GeoUtils.js +76 -0
- package/build/map/utils/OfflineMapManager.d.ts +148 -0
- package/build/map/utils/OfflineMapManager.js +217 -0
- package/build/map/utils/PermissionUtils.d.ts +91 -0
- package/build/map/utils/PermissionUtils.js +255 -0
- package/build/map/utils/PlatformDetector.d.ts +102 -0
- package/build/map/utils/PlatformDetector.js +186 -0
- package/build/types/naviview.types.d.ts +1 -1
- package/expo-module.config.json +12 -10
- package/ios/ExpoGaodeMapNavigation.podspec +9 -0
- package/ios/map/ExpoGaodeMapModule.swift +485 -75
- package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
- package/ios/map/ExpoGaodeMapView.swift +611 -62
- package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
- package/ios/map/MapPreloadManager.swift +348 -0
- package/ios/map/cpp/ClusterEngine.cpp +110 -0
- package/ios/map/cpp/ClusterEngine.hpp +20 -0
- package/ios/map/cpp/ColorParser.cpp +135 -0
- package/ios/map/cpp/ColorParser.hpp +14 -0
- package/ios/map/cpp/GeometryEngine.cpp +574 -0
- package/ios/map/cpp/GeometryEngine.hpp +159 -0
- package/ios/map/cpp/QuadTree.cpp +92 -0
- package/ios/map/cpp/QuadTree.hpp +42 -0
- package/ios/map/cpp/README.md +55 -0
- package/ios/map/cpp/tests/benchmark_js.js +41 -0
- package/ios/map/cpp/tests/run.sh +17 -0
- package/ios/map/cpp/tests/test_main.cpp +276 -0
- package/ios/map/managers/UIManager.swift +72 -1
- package/ios/map/modules/LocationManager.swift +114 -165
- package/ios/map/overlays/CircleView.swift +16 -32
- package/ios/map/overlays/CircleViewModule.swift +12 -12
- package/ios/map/overlays/ClusterAnnotation.swift +32 -0
- package/ios/map/overlays/ClusterView.swift +331 -45
- package/ios/map/overlays/ClusterViewModule.swift +20 -6
- package/ios/map/overlays/HeatMapView.swift +135 -32
- package/ios/map/overlays/HeatMapViewModule.swift +20 -8
- package/ios/map/overlays/MarkerView.swift +613 -130
- package/ios/map/overlays/MarkerViewModule.swift +38 -18
- package/ios/map/overlays/MultiPointView.swift +168 -10
- package/ios/map/overlays/MultiPointViewModule.swift +27 -5
- package/ios/map/overlays/PolygonView.swift +62 -23
- package/ios/map/overlays/PolygonViewModule.swift +18 -12
- package/ios/map/overlays/PolylineView.swift +21 -13
- package/ios/map/overlays/PolylineViewModule.swift +18 -12
- package/ios/map/utils/ClusterNative.h +96 -0
- package/ios/map/utils/ClusterNative.mm +377 -0
- package/ios/map/utils/ColorParser.swift +12 -1
- package/ios/map/utils/CppBridging.mm +13 -0
- package/ios/map/utils/GeometryUtils.swift +34 -0
- package/ios/map/utils/LatLngParser.swift +87 -0
- package/ios/map/utils/PermissionManager.swift +135 -6
- package/package.json +1 -1
- package/build/map/ExpoGaodeMap.types.d.ts +0 -41
- package/build/map/ExpoGaodeMap.types.js +0 -24
- package/build/map/utils/EventManager.d.ts +0 -10
- package/build/map/utils/EventManager.js +0 -26
- package/build/map/utils/ModuleLoader.d.ts +0 -73
- package/build/map/utils/ModuleLoader.js +0 -112
|
@@ -3,6 +3,7 @@ package expo.modules.gaodemap.map
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
6
7
|
import com.amap.api.maps.AMap
|
|
7
8
|
import com.amap.api.maps.MapView
|
|
8
9
|
import com.amap.api.maps.MapsInitializer
|
|
@@ -12,8 +13,10 @@ import expo.modules.kotlin.viewevent.EventDispatcher
|
|
|
12
13
|
import expo.modules.kotlin.views.ExpoView
|
|
13
14
|
import expo.modules.gaodemap.map.managers.CameraManager
|
|
14
15
|
import expo.modules.gaodemap.map.managers.UIManager
|
|
15
|
-
import expo.modules.gaodemap.map.overlays.CircleView
|
|
16
16
|
import expo.modules.gaodemap.map.overlays.*
|
|
17
|
+
import androidx.core.graphics.createBitmap
|
|
18
|
+
import androidx.core.view.isVisible
|
|
19
|
+
import androidx.core.graphics.withTranslation
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* 高德地图视图组件
|
|
@@ -24,6 +27,8 @@ import expo.modules.gaodemap.map.overlays.*
|
|
|
24
27
|
* - 相机控制和覆盖物管理
|
|
25
28
|
* - 生命周期管理
|
|
26
29
|
*/
|
|
30
|
+
|
|
31
|
+
@SuppressLint("ViewConstructor")
|
|
27
32
|
class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
28
33
|
|
|
29
34
|
/**
|
|
@@ -45,6 +50,8 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
45
50
|
internal var initialCameraPosition: Map<String, Any?>? = null
|
|
46
51
|
/** 是否跟随用户位置 */
|
|
47
52
|
internal var followUserLocation: Boolean = false
|
|
53
|
+
/** 自定义地图样式配置(缓存) */
|
|
54
|
+
private var customMapStyleData: Map<String, Any>? = null
|
|
48
55
|
|
|
49
56
|
/** 主线程 Handler */
|
|
50
57
|
private val mainHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
@@ -57,6 +64,21 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
57
64
|
private val onCameraMove by EventDispatcher()
|
|
58
65
|
private val onCameraIdle by EventDispatcher()
|
|
59
66
|
|
|
67
|
+
// 事件节流控制
|
|
68
|
+
/** 相机移动事件节流间隔(毫秒) */
|
|
69
|
+
private val CAMERA_MOVE_THROTTLE_MS = 100L
|
|
70
|
+
/** 上次触发相机移动事件的时间戳 */
|
|
71
|
+
private var lastCameraMoveTime = 0L
|
|
72
|
+
/** 缓存的相机移动事件数据 */
|
|
73
|
+
private var pendingCameraMoveData: Map<String, Any>? = null
|
|
74
|
+
/** 节流定时器 Runnable */
|
|
75
|
+
private val throttleRunnable = Runnable {
|
|
76
|
+
pendingCameraMoveData?.let { data ->
|
|
77
|
+
onCameraMove(data)
|
|
78
|
+
pendingCameraMoveData = null
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
60
82
|
// 高德地图视图
|
|
61
83
|
private lateinit var mapView: MapView
|
|
62
84
|
private lateinit var aMap: AMap
|
|
@@ -75,9 +97,19 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
75
97
|
MapsInitializer.updatePrivacyShow(context, true, true)
|
|
76
98
|
MapsInitializer.updatePrivacyAgree(context, true)
|
|
77
99
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
100
|
+
// 尝试从预加载池获取 MapView
|
|
101
|
+
val preloadedMapView = MapPreloadManager.getPreloadedMapView()
|
|
102
|
+
|
|
103
|
+
if (preloadedMapView != null) {
|
|
104
|
+
mapView = preloadedMapView
|
|
105
|
+
android.util.Log.i("ExpoGaodeMapView", "🚀 使用预加载的 MapView 实例")
|
|
106
|
+
} else {
|
|
107
|
+
// 创建地图视图
|
|
108
|
+
mapView = MapView(context)
|
|
109
|
+
mapView.onCreate(null)
|
|
110
|
+
android.util.Log.i("ExpoGaodeMapView", "⚠️ 创建新的 MapView 实例 (未命中预加载池)")
|
|
111
|
+
}
|
|
112
|
+
|
|
81
113
|
aMap = mapView.map
|
|
82
114
|
|
|
83
115
|
// 初始化管理器
|
|
@@ -115,6 +147,11 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
115
147
|
pendingCameraPosition = null
|
|
116
148
|
}
|
|
117
149
|
|
|
150
|
+
// 应用缓存的自定义地图样式
|
|
151
|
+
customMapStyleData?.let { styleData ->
|
|
152
|
+
uiManager.setCustomMapStyle(styleData)
|
|
153
|
+
}
|
|
154
|
+
|
|
118
155
|
onLoad(mapOf("loaded" to true))
|
|
119
156
|
}
|
|
120
157
|
} catch (_: Exception) {
|
|
@@ -122,6 +159,19 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
122
159
|
}
|
|
123
160
|
}
|
|
124
161
|
|
|
162
|
+
// 辅助监听器列表
|
|
163
|
+
private val cameraChangeListeners = mutableListOf<AMap.OnCameraChangeListener>()
|
|
164
|
+
|
|
165
|
+
fun addCameraChangeListener(listener: AMap.OnCameraChangeListener) {
|
|
166
|
+
if (!cameraChangeListeners.contains(listener)) {
|
|
167
|
+
cameraChangeListeners.add(listener)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
fun removeCameraChangeListener(listener: AMap.OnCameraChangeListener) {
|
|
172
|
+
cameraChangeListeners.remove(listener)
|
|
173
|
+
}
|
|
174
|
+
|
|
125
175
|
/**
|
|
126
176
|
* 设置地图事件监听
|
|
127
177
|
*/
|
|
@@ -129,10 +179,14 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
129
179
|
// 设置相机移动监听器
|
|
130
180
|
aMap.setOnCameraChangeListener(object : AMap.OnCameraChangeListener {
|
|
131
181
|
override fun onCameraChange(cameraPosition: com.amap.api.maps.model.CameraPosition?) {
|
|
132
|
-
//
|
|
182
|
+
// 通知辅助监听器
|
|
183
|
+
cameraChangeListeners.forEach { it.onCameraChange(cameraPosition) }
|
|
184
|
+
|
|
185
|
+
// 相机移动中 - 应用节流优化
|
|
133
186
|
cameraPosition?.let {
|
|
187
|
+
val currentTime = System.currentTimeMillis()
|
|
134
188
|
val visibleRegion = aMap.projection.visibleRegion
|
|
135
|
-
|
|
189
|
+
val eventData = mapOf(
|
|
136
190
|
"cameraPosition" to mapOf(
|
|
137
191
|
"target" to mapOf(
|
|
138
192
|
"latitude" to it.target.latitude,
|
|
@@ -152,11 +206,32 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
152
206
|
"longitude" to visibleRegion.nearLeft.longitude
|
|
153
207
|
)
|
|
154
208
|
)
|
|
155
|
-
)
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
// 节流逻辑:100ms 内只触发一次
|
|
212
|
+
if (currentTime - lastCameraMoveTime >= CAMERA_MOVE_THROTTLE_MS) {
|
|
213
|
+
// 超过节流时间,立即触发事件
|
|
214
|
+
lastCameraMoveTime = currentTime
|
|
215
|
+
onCameraMove(eventData)
|
|
216
|
+
// 清除待处理的事件和定时器
|
|
217
|
+
mainHandler.removeCallbacks(throttleRunnable)
|
|
218
|
+
pendingCameraMoveData = null
|
|
219
|
+
} else {
|
|
220
|
+
// 在节流时间内,缓存事件数据,使用定时器延迟触发
|
|
221
|
+
pendingCameraMoveData = eventData
|
|
222
|
+
mainHandler.removeCallbacks(throttleRunnable)
|
|
223
|
+
mainHandler.postDelayed(
|
|
224
|
+
throttleRunnable,
|
|
225
|
+
CAMERA_MOVE_THROTTLE_MS - (currentTime - lastCameraMoveTime)
|
|
226
|
+
)
|
|
227
|
+
}
|
|
156
228
|
}
|
|
157
229
|
}
|
|
158
230
|
|
|
159
231
|
override fun onCameraChangeFinish(cameraPosition: com.amap.api.maps.model.CameraPosition?) {
|
|
232
|
+
// 通知辅助监听器
|
|
233
|
+
cameraChangeListeners.forEach { it.onCameraChangeFinish(cameraPosition) }
|
|
234
|
+
|
|
160
235
|
// 相机移动完成
|
|
161
236
|
cameraPosition?.let {
|
|
162
237
|
val visibleRegion = aMap.projection.visibleRegion
|
|
@@ -187,7 +262,13 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
187
262
|
|
|
188
263
|
// 设置全局 Marker 点击监听器
|
|
189
264
|
aMap.setOnMarkerClickListener { marker ->
|
|
190
|
-
MarkerView.handleMarkerClick(marker)
|
|
265
|
+
if (MarkerView.handleMarkerClick(marker)) {
|
|
266
|
+
return@setOnMarkerClickListener true
|
|
267
|
+
}
|
|
268
|
+
if (ClusterView.handleMarkerClick(marker)) {
|
|
269
|
+
return@setOnMarkerClickListener true
|
|
270
|
+
}
|
|
271
|
+
false
|
|
191
272
|
}
|
|
192
273
|
|
|
193
274
|
// 设置全局 Marker 拖拽监听器
|
|
@@ -205,6 +286,19 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
205
286
|
}
|
|
206
287
|
})
|
|
207
288
|
|
|
289
|
+
// 设置全局 MultiPoint 点击监听器
|
|
290
|
+
aMap.setOnMultiPointClickListener { item ->
|
|
291
|
+
for (i in 0 until childCount) {
|
|
292
|
+
val child = getChildAt(i)
|
|
293
|
+
if (child is MultiPointView) {
|
|
294
|
+
if (child.handleMultiPointClick(item)) {
|
|
295
|
+
return@setOnMultiPointClickListener true
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return@setOnMultiPointClickListener false
|
|
300
|
+
}
|
|
301
|
+
|
|
208
302
|
aMap.setOnMapClickListener { latLng ->
|
|
209
303
|
// 检查声明式 PolylineView
|
|
210
304
|
if (checkDeclarativePolylinePress(latLng)) {
|
|
@@ -331,6 +425,18 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
331
425
|
fun setShowsBuildings(show: Boolean) = uiManager.setShowsBuildings(show)
|
|
332
426
|
/** 设置是否显示室内地图 */
|
|
333
427
|
fun setShowsIndoorMap(show: Boolean) = uiManager.setShowsIndoorMap(show)
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* 设置自定义地图样式
|
|
431
|
+
* @param styleData 样式配置
|
|
432
|
+
*/
|
|
433
|
+
fun setCustomMapStyle(styleData: Map<String, Any>) {
|
|
434
|
+
customMapStyleData = styleData
|
|
435
|
+
// 如果地图已加载,立即应用样式
|
|
436
|
+
if (isMapLoaded) {
|
|
437
|
+
uiManager.setCustomMapStyle(styleData)
|
|
438
|
+
}
|
|
439
|
+
}
|
|
334
440
|
|
|
335
441
|
// ==================== 相机控制方法 ====================
|
|
336
442
|
|
|
@@ -378,8 +484,106 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
378
484
|
return cameraManager.getCameraPosition()
|
|
379
485
|
}
|
|
380
486
|
|
|
487
|
+
/**
|
|
488
|
+
* 截取地图快照
|
|
489
|
+
* @param promise Promise
|
|
490
|
+
*/
|
|
491
|
+
fun takeSnapshot(promise: expo.modules.kotlin.Promise) {
|
|
492
|
+
val isSettled = java.util.concurrent.atomic.AtomicBoolean(false)
|
|
493
|
+
|
|
494
|
+
aMap.getMapScreenShot(object : AMap.OnMapScreenShotListener {
|
|
495
|
+
override fun onMapScreenShot(bitmap: android.graphics.Bitmap?) {
|
|
496
|
+
// 如果已经处理过,直接返回
|
|
497
|
+
if (isSettled.getAndSet(true)) return
|
|
498
|
+
|
|
499
|
+
// 旧版本回调,为了兼容性也处理
|
|
500
|
+
bitmap?.let { handleSnapshot(it, promise) } ?: run {
|
|
501
|
+
promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
381
504
|
|
|
382
|
-
|
|
505
|
+
override fun onMapScreenShot(bitmap: android.graphics.Bitmap?, status: Int) {
|
|
506
|
+
// 如果已经处理过,直接返回
|
|
507
|
+
if (isSettled.getAndSet(true)) return
|
|
508
|
+
|
|
509
|
+
// status != 0 表示失败
|
|
510
|
+
if (status != 0) {
|
|
511
|
+
promise.reject("SNAPSHOT_FAILED", "Failed to take snapshot, status code: $status", null)
|
|
512
|
+
return
|
|
513
|
+
}
|
|
514
|
+
bitmap?.let { handleSnapshot(it, promise) } ?: run {
|
|
515
|
+
promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
})
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
@SuppressLint("WrongThread")
|
|
522
|
+
private fun handleSnapshot(mapBitmap: android.graphics.Bitmap, promise: expo.modules.kotlin.Promise) {
|
|
523
|
+
try {
|
|
524
|
+
// 创建最终的 Bitmap,大小为当前容器的大小
|
|
525
|
+
val width = this.width
|
|
526
|
+
val height = this.height
|
|
527
|
+
|
|
528
|
+
// 如果容器宽高为0,无法截图
|
|
529
|
+
if (width <= 0 || height <= 0) {
|
|
530
|
+
promise.reject("SNAPSHOT_FAILED", "View dimensions are invalid", null)
|
|
531
|
+
return
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
val finalBitmap = createBitmap(width, height)
|
|
535
|
+
val canvas = android.graphics.Canvas(finalBitmap)
|
|
536
|
+
|
|
537
|
+
// 1. 绘制地图底图
|
|
538
|
+
canvas.drawBitmap(mapBitmap, mapView.left.toFloat(), mapView.top.toFloat(), null)
|
|
539
|
+
|
|
540
|
+
// 2. 绘制内部子视图 (React Native Overlays, e.g. Callout)
|
|
541
|
+
for (i in 0 until childCount) {
|
|
542
|
+
val child = getChildAt(i)
|
|
543
|
+
val isMarkerView = child is MarkerView
|
|
544
|
+
|
|
545
|
+
// 跳过地图本身、隐藏的视图以及 MarkerView
|
|
546
|
+
if (child !== mapView && child.isVisible && !isMarkerView) {
|
|
547
|
+
canvas.withTranslation(child.left.toFloat(), child.top.toFloat()) {
|
|
548
|
+
child.draw(this)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// 3. 绘制兄弟视图 (MapUI, 覆盖在地图上的 UI 组件)
|
|
554
|
+
// 模仿 iOS 的实现:遍历父容器的子视图,绘制那些覆盖在地图上方的兄弟节点
|
|
555
|
+
(parent as? ViewGroup)?.let { parentGroup ->
|
|
556
|
+
for (i in 0 until parentGroup.childCount) {
|
|
557
|
+
val sibling = parentGroup.getChildAt(i)
|
|
558
|
+
// 跳过自己(地图本身)和隐藏的视图
|
|
559
|
+
if (sibling !== this && sibling.isVisible) {
|
|
560
|
+
// 计算相对坐标:兄弟视图相对于父容器的坐标 - 地图相对于父容器的坐标
|
|
561
|
+
val dx = sibling.left - this.left
|
|
562
|
+
val dy = sibling.top - this.top
|
|
563
|
+
|
|
564
|
+
canvas.withTranslation(dx.toFloat(), dy.toFloat()) {
|
|
565
|
+
sibling.draw(this)
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// 3. 保存到文件
|
|
572
|
+
val filename = java.util.UUID.randomUUID().toString() + ".png"
|
|
573
|
+
val file = java.io.File(context.cacheDir, filename)
|
|
574
|
+
val stream = java.io.FileOutputStream(file)
|
|
575
|
+
finalBitmap.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, stream)
|
|
576
|
+
stream.close()
|
|
577
|
+
|
|
578
|
+
// 4. 返回文件路径
|
|
579
|
+
promise.resolve(file.absolutePath)
|
|
580
|
+
|
|
581
|
+
} catch (e: Exception) {
|
|
582
|
+
promise.reject("SNAPSHOT_ERROR", "Error processing snapshot: ${e.message}", e)
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ==================== 生命周期管理 ====================
|
|
383
587
|
|
|
384
588
|
/** 恢复地图 */
|
|
385
589
|
@Suppress("unused")
|
|
@@ -397,8 +601,12 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
397
601
|
@Suppress("unused")
|
|
398
602
|
fun onDestroy() {
|
|
399
603
|
try {
|
|
400
|
-
|
|
401
|
-
|
|
604
|
+
// 清理节流定时器
|
|
605
|
+
mainHandler.removeCallbacks(throttleRunnable)
|
|
606
|
+
pendingCameraMoveData = null
|
|
607
|
+
|
|
608
|
+
// 清理 Handler 回调,防止内存泄露
|
|
609
|
+
mainHandler.removeCallbacksAndMessages(null)
|
|
402
610
|
|
|
403
611
|
// 清理所有地图监听器
|
|
404
612
|
aMap.setOnMapClickListener(null)
|
|
@@ -407,6 +615,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
407
615
|
aMap.setOnCameraChangeListener(null)
|
|
408
616
|
aMap.setOnMarkerClickListener(null)
|
|
409
617
|
aMap.setOnMarkerDragListener(null)
|
|
618
|
+
aMap.setOnMultiPointClickListener(null)
|
|
410
619
|
|
|
411
620
|
// 清除所有覆盖物
|
|
412
621
|
aMap.clear()
|
|
@@ -466,10 +675,14 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
466
675
|
|
|
467
676
|
/**
|
|
468
677
|
* 移除子视图
|
|
678
|
+
* 延迟移除 Marker,让它们跟随地图一起延迟销毁
|
|
469
679
|
*/
|
|
470
680
|
override fun removeView(child: View?) {
|
|
471
681
|
if (child is MarkerView) {
|
|
472
|
-
|
|
682
|
+
// 延迟移除 Marker,与地图的延迟销毁时间一致(500ms)
|
|
683
|
+
mainHandler.postDelayed({
|
|
684
|
+
child.removeMarker()
|
|
685
|
+
}, 500)
|
|
473
686
|
super.removeView(child)
|
|
474
687
|
return
|
|
475
688
|
}
|
|
@@ -483,6 +696,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
483
696
|
|
|
484
697
|
/**
|
|
485
698
|
* 按索引移除视图
|
|
699
|
+
* 延迟移除 Marker,让它们跟随地图一起延迟销毁
|
|
486
700
|
*/
|
|
487
701
|
override fun removeViewAt(index: Int) {
|
|
488
702
|
try {
|
|
@@ -493,7 +707,10 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
493
707
|
}
|
|
494
708
|
|
|
495
709
|
if (child is MarkerView) {
|
|
496
|
-
|
|
710
|
+
// 延迟移除 Marker,与地图的延迟销毁时间一致(500ms)
|
|
711
|
+
mainHandler.postDelayed({
|
|
712
|
+
child.removeMarker()
|
|
713
|
+
}, 500)
|
|
497
714
|
}
|
|
498
715
|
|
|
499
716
|
super.removeViewAt(index)
|
|
@@ -542,5 +759,4 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
542
759
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
543
760
|
super.onLayout(changed, left, top, right, bottom)
|
|
544
761
|
}
|
|
545
|
-
|
|
546
762
|
}
|
|
@@ -3,22 +3,24 @@ package expo.modules.gaodemap.map
|
|
|
3
3
|
import expo.modules.kotlin.modules.Module
|
|
4
4
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
/**
|
|
8
7
|
* 高德地图视图 Module
|
|
9
8
|
*/
|
|
10
9
|
class ExpoGaodeMapViewModule : Module() {
|
|
11
10
|
override fun definition() = ModuleDefinition {
|
|
12
|
-
Name("
|
|
11
|
+
Name("ExpoGaodeMapView")
|
|
13
12
|
|
|
14
13
|
View(ExpoGaodeMapView::class) {
|
|
15
14
|
Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onCameraMove", "onCameraIdle")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// 延迟销毁地图,避免页面退出动画未完成时地图就变成白屏
|
|
19
|
+
OnViewDestroys { view: ExpoGaodeMapView ->
|
|
20
|
+
// 延迟 500ms 销毁地图,让页面退出动画先完成
|
|
21
|
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
22
|
+
view.onDestroy()
|
|
23
|
+
}, 500)
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
|
|
@@ -40,7 +42,7 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
40
42
|
Prop<Boolean>("scrollGesturesEnabled") { view, enabled -> view.setScrollEnabled(enabled) }
|
|
41
43
|
Prop<Boolean>("rotateGesturesEnabled") { view, enabled -> view.setRotateEnabled(enabled) }
|
|
42
44
|
Prop<Boolean>("tiltGesturesEnabled") { view, enabled -> view.setTiltEnabled(enabled) }
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
Prop<Float>("maxZoom") { view, maxZoom -> view.setMaxZoom(maxZoom) }
|
|
45
47
|
Prop<Float>("minZoom") { view, minZoom -> view.setMinZoom(minZoom) }
|
|
46
48
|
|
|
@@ -52,36 +54,44 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
52
54
|
Prop<Boolean>("trafficEnabled") { view, show -> view.setShowsTraffic(show) }
|
|
53
55
|
Prop<Boolean>("buildingsEnabled") { view, show -> view.setShowsBuildings(show) }
|
|
54
56
|
Prop<Boolean>("indoorViewEnabled") { view, show -> view.setShowsIndoorMap(show) }
|
|
57
|
+
|
|
58
|
+
Prop<Map<String, Any>?>("customMapStyle") { view, styleData ->
|
|
59
|
+
styleData?.let { view.setCustomMapStyle(it) }
|
|
60
|
+
}
|
|
55
61
|
|
|
56
|
-
OnViewDidUpdateProps { view ->
|
|
62
|
+
OnViewDidUpdateProps { view: ExpoGaodeMapView ->
|
|
57
63
|
if (view.mapType != 0) {
|
|
58
64
|
view.setMapType(view.mapType)
|
|
59
65
|
}
|
|
60
|
-
|
|
66
|
+
|
|
61
67
|
view.initialCameraPosition?.let { position ->
|
|
62
68
|
view.setInitialCameraPosition(position)
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
AsyncFunction("moveCamera") { view: ExpoGaodeMapView, position: Map<String, Any>, duration: Int ->
|
|
73
|
+
view.moveCamera(position, duration)
|
|
74
|
+
}
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
AsyncFunction("getLatLng") { view: ExpoGaodeMapView, point: Map<String, Double> ->
|
|
77
|
+
view.getLatLng(point)
|
|
78
|
+
}
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
AsyncFunction("takeSnapshot") { view: ExpoGaodeMapView, promise: expo.modules.kotlin.Promise ->
|
|
81
|
+
view.takeSnapshot(promise)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
AsyncFunction("setCenter") { view: ExpoGaodeMapView, center: Map<String, Double>, animated: Boolean ->
|
|
85
|
+
view.setCenter(center, animated)
|
|
86
|
+
}
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
AsyncFunction("setZoom") { view: ExpoGaodeMapView, zoom: Double, animated: Boolean ->
|
|
89
|
+
view.setZoomLevel(zoom.toFloat(), animated)
|
|
90
|
+
}
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
AsyncFunction("getCameraPosition") { view: ExpoGaodeMapView ->
|
|
93
|
+
view.getCameraPosition()
|
|
94
|
+
}
|
|
85
95
|
}
|
|
86
96
|
}
|
|
87
|
-
}
|
|
97
|
+
}
|