expo-gaode-map 2.0.0-alpha.3 → 2.0.0-alpha.4

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.md CHANGED
@@ -372,7 +372,7 @@ export default function LocationApp() {
372
372
  ExpoGaodeMapModule.setInterval(2000); // 2秒更新一次
373
373
 
374
374
  // 监听位置更新
375
- const subscription = ExpoGaodeMapModule.addListener('onLocationUpdate', (loc) => {
375
+ const subscription = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (loc) => {
376
376
  console.log('位置更新:', loc);
377
377
  setLocation(loc);
378
378
  });
@@ -2,7 +2,6 @@ package expo.modules.gaodemap
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
- import android.util.Log
6
5
  import android.view.View
7
6
  import com.amap.api.maps.AMap
8
7
  import com.amap.api.maps.MapView
@@ -34,15 +33,11 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
34
33
  override fun requestLayout() {
35
34
  try {
36
35
  super.requestLayout()
37
- } catch (e: Exception) {
36
+ } catch (_: Exception) {
38
37
  // 忽略异常
39
38
  }
40
39
  }
41
40
 
42
- companion object {
43
- private const val TAG = "ExpoGaodeMapView"
44
- }
45
-
46
41
  // Props 存储
47
42
  /** 地图类型 */
48
43
  internal var mapType: Int = 0
@@ -122,7 +117,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
122
117
 
123
118
  onLoad(mapOf("loaded" to true))
124
119
  }
125
- } catch (e: Exception) {
120
+ } catch (_: Exception) {
126
121
  // 初始化失败,静默处理
127
122
  }
128
123
  }
@@ -438,7 +433,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
438
433
  return
439
434
  }
440
435
 
441
- if (child is com.amap.api.maps.MapView) {
436
+ if (child is MapView) {
442
437
  super.addView(child, index)
443
438
  return
444
439
  }
@@ -469,7 +464,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
469
464
 
470
465
  try {
471
466
  super.removeView(child)
472
- } catch (e: Exception) {
467
+ } catch (_: Exception) {
473
468
  // 忽略异常
474
469
  }
475
470
  }
@@ -481,7 +476,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
481
476
  try {
482
477
  val child = super.getChildAt(index)
483
478
 
484
- if (child is com.amap.api.maps.MapView) {
479
+ if (child is MapView) {
485
480
  return
486
481
  }
487
482
 
@@ -491,7 +486,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
491
486
 
492
487
  super.removeViewAt(index)
493
488
 
494
- } catch (e: Exception) {
489
+ } catch (_: Exception) {
495
490
  // 忽略异常
496
491
  }
497
492
  }
@@ -14,7 +14,7 @@ class ExpoGaodeMapViewModule : Module() {
14
14
  Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onCameraMove", "onCameraIdle")
15
15
 
16
16
  // ✅ 关键修复:拦截 React Native 的视图操作异常
17
- OnViewDestroys { view: ExpoGaodeMapView ->
17
+ OnViewDestroys { _: ExpoGaodeMapView ->
18
18
  }
19
19
 
20
20
  Prop<Int>("mapType") { view, type ->
@@ -4,15 +4,14 @@ import android.content.Context
4
4
  import android.graphics.BitmapFactory
5
5
  import android.location.Location
6
6
  import android.location.LocationListener
7
- import android.location.LocationManager as AndroidLocationManager
8
7
  import android.os.Bundle
9
8
  import com.amap.api.maps.AMap
10
9
  import com.amap.api.maps.LocationSource
11
10
  import com.amap.api.maps.model.BitmapDescriptorFactory
12
11
  import com.amap.api.maps.model.MyLocationStyle
13
12
  import expo.modules.gaodemap.utils.ColorParser
14
- import java.io.File
15
13
  import java.net.URL
14
+ import androidx.core.graphics.scale
16
15
 
17
16
  /**
18
17
  * UI 和手势管理器
@@ -22,7 +21,6 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
22
21
 
23
22
  var onLocationChanged: ((latitude: Double, longitude: Double, accuracy: Float) -> Unit)? = null
24
23
 
25
- private var locationManager: AndroidLocationManager? = null
26
24
  private var locationChangedListener: LocationSource.OnLocationChangedListener? = null
27
25
 
28
26
  // ==================== 控件显示 ====================
@@ -134,61 +132,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
134
132
  }
135
133
  }
136
134
 
137
- /**
138
- * 启动真实的系统定位
139
- */
140
- private fun startRealLocation() {
141
- try {
142
- if (locationManager == null) {
143
- locationManager = context.getSystemService(Context.LOCATION_SERVICE) as AndroidLocationManager
144
- }
145
-
146
- val providers = locationManager?.getProviders(true) ?: emptyList()
147
-
148
- val provider = when {
149
- providers.contains(AndroidLocationManager.GPS_PROVIDER) -> {
150
- AndroidLocationManager.GPS_PROVIDER
151
- }
152
- providers.contains(AndroidLocationManager.NETWORK_PROVIDER) -> {
153
- AndroidLocationManager.NETWORK_PROVIDER
154
- }
155
- else -> {
156
- return
157
- }
158
- }
159
-
160
- // 请求位置更新
161
- locationManager?.requestLocationUpdates(
162
- provider,
163
- 2000L, // 最小时间间隔 2秒
164
- 10f, // 最小距离变化 10米
165
- this
166
- )
167
-
168
- // 立即获取最后已知位置
169
- val lastLocation = locationManager?.getLastKnownLocation(provider)
170
- if (lastLocation != null) {
171
- onLocationChanged(lastLocation)
172
- }
173
-
174
- } catch (e: SecurityException) {
175
- // 忽略异常
176
- } catch (e: Exception) {
177
- // 忽略异常
178
- }
179
- }
180
-
181
- /**
182
- * 停止系统定位
183
- */
184
- private fun stopRealLocation() {
185
- try {
186
- locationManager?.removeUpdates(this)
187
- } catch (e: Exception) {
188
- // 忽略异常
189
- }
190
- }
191
-
135
+
192
136
  /**
193
137
  * 位置变化回调
194
138
  */
@@ -268,7 +212,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
268
212
  android.os.Handler(android.os.Looper.getMainLooper()).post {
269
213
  if (originalBitmap != null) {
270
214
  val scaledBitmap = if (imageWidth != null && imageHeight != null) {
271
- android.graphics.Bitmap.createScaledBitmap(originalBitmap, imageWidth, imageHeight, true)
215
+ originalBitmap.scale(imageWidth, imageHeight)
272
216
  } else originalBitmap
273
217
 
274
218
  style.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap))
@@ -282,7 +226,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
282
226
  }
283
227
  }
284
228
  }
285
- } catch (e: Exception) {
229
+ } catch (_: Exception) {
286
230
  // 忽略异常
287
231
  }
288
232
  }.start()
@@ -313,7 +257,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
313
257
  android.os.Handler(android.os.Looper.getMainLooper()).post {
314
258
  if (originalBitmap != null) {
315
259
  val scaledBitmap = if (imageWidth != null && imageHeight != null) {
316
- android.graphics.Bitmap.createScaledBitmap(originalBitmap, imageWidth, imageHeight, true)
260
+ originalBitmap.scale(imageWidth, imageHeight)
317
261
  } else originalBitmap
318
262
 
319
263
  style.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap))
@@ -327,7 +271,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
327
271
  }
328
272
  }
329
273
  }
330
- } catch (e: Exception) {
274
+ } catch (_: Exception) {
331
275
  // 忽略异常
332
276
  }
333
277
  }.start()
@@ -18,9 +18,7 @@ import expo.modules.gaodemap.services.LocationForegroundService
18
18
  * - 定位结果回调
19
19
  */
20
20
  class LocationManager(context: Context) {
21
- companion object {
22
- private const val TAG = "LocationManager"
23
- }
21
+
24
22
 
25
23
  /** 应用上下文(避免 Activity 泄露) */
26
24
  private val appContext: Context = context.applicationContext
@@ -1,7 +1,6 @@
1
1
  package expo.modules.gaodemap.modules
2
2
 
3
3
  import android.content.Context
4
- import android.util.Log
5
4
  import com.amap.api.location.AMapLocationClient
6
5
  import com.amap.api.maps.MapsInitializer
7
6
 
@@ -15,7 +14,7 @@ import com.amap.api.maps.MapsInitializer
15
14
  * - 获取 SDK 版本信息
16
15
  */
17
16
  object SDKInitializer {
18
- private const val TAG = "SDKInitializer"
17
+
19
18
 
20
19
  /**
21
20
  * 初始化高德地图和定位 SDK
@@ -154,8 +154,16 @@ class CircleView(context: Context, appContext: AppContext) : ExpoView(context, a
154
154
 
155
155
  override fun onDetachedFromWindow() {
156
156
  super.onDetachedFromWindow()
157
- removeCircle()
158
- aMap = null
157
+ // 🔑 关键修复:使用 post 延迟检查,避免 TabView 切换时误删
158
+ // 如果是真正的移除,parent 会保持为 null
159
+ // 如果只是 TabView 切换,parent 会在短时间内恢复
160
+ post {
161
+ // 延迟后再次检查 parent,如果仍然为 null,说明是真正的移除
162
+ if (parent == null) {
163
+ removeCircle()
164
+ aMap = null
165
+ }
166
+ }
159
167
  }
160
168
 
161
169
  }
@@ -128,7 +128,12 @@ class ClusterView(context: Context, appContext: AppContext) : ExpoView(context,
128
128
 
129
129
  override fun onDetachedFromWindow() {
130
130
  super.onDetachedFromWindow()
131
- removeCluster()
132
- aMap = null
131
+ // 🔑 关键修复:使用 post 延迟检查
132
+ post {
133
+ if (parent == null) {
134
+ removeCluster()
135
+ aMap = null
136
+ }
137
+ }
133
138
  }
134
139
  }
@@ -94,7 +94,12 @@ class HeatMapView(context: Context, appContext: AppContext) : ExpoView(context,
94
94
 
95
95
  override fun onDetachedFromWindow() {
96
96
  super.onDetachedFromWindow()
97
- removeHeatMap()
98
- aMap = null
97
+ // 🔑 关键修复:使用 post 延迟检查
98
+ post {
99
+ if (parent == null) {
100
+ removeHeatMap()
101
+ aMap = null
102
+ }
103
+ }
99
104
  }
100
105
  }
@@ -19,11 +19,16 @@ import com.amap.api.maps.model.MarkerOptions
19
19
  import expo.modules.kotlin.AppContext
20
20
  import expo.modules.kotlin.viewevent.EventDispatcher
21
21
  import expo.modules.kotlin.views.ExpoView
22
- import java.io.File
23
22
  import java.io.InputStream
24
23
  import java.net.HttpURLConnection
25
24
  import java.net.URL
26
25
  import kotlin.concurrent.thread
26
+ import androidx.core.view.isNotEmpty
27
+ import androidx.core.view.contains
28
+ import androidx.core.graphics.createBitmap
29
+ import androidx.core.view.isEmpty
30
+ import androidx.core.graphics.toColorInt
31
+ import androidx.core.graphics.scale
27
32
 
28
33
  class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
29
34
 
@@ -35,24 +40,24 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
35
40
  orientation = HORIZONTAL
36
41
  }
37
42
 
38
- override fun generateDefaultLayoutParams(): android.widget.LinearLayout.LayoutParams {
39
- return android.widget.LinearLayout.LayoutParams(
40
- android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
41
- android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
43
+ override fun generateDefaultLayoutParams(): LayoutParams {
44
+ return LayoutParams(
45
+ LayoutParams.WRAP_CONTENT,
46
+ LayoutParams.WRAP_CONTENT
42
47
  )
43
48
  }
44
49
 
45
- override fun generateLayoutParams(attrs: android.util.AttributeSet?): android.widget.LinearLayout.LayoutParams {
46
- return android.widget.LinearLayout.LayoutParams(context, attrs)
50
+ override fun generateLayoutParams(attrs: android.util.AttributeSet?): LayoutParams {
51
+ return LayoutParams(context, attrs)
47
52
  }
48
53
 
49
- override fun generateLayoutParams(lp: android.view.ViewGroup.LayoutParams?): android.widget.LinearLayout.LayoutParams {
54
+ override fun generateLayoutParams(lp: android.view.ViewGroup.LayoutParams?): LayoutParams {
50
55
  return when (lp) {
51
- is android.widget.LinearLayout.LayoutParams -> lp
52
- is android.view.ViewGroup.MarginLayoutParams -> android.widget.LinearLayout.LayoutParams(lp)
53
- else -> android.widget.LinearLayout.LayoutParams(
54
- lp?.width ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
55
- lp?.height ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
56
+ is LayoutParams -> lp
57
+ is MarginLayoutParams -> android.widget.LinearLayout.LayoutParams(lp)
58
+ else -> LayoutParams(
59
+ lp?.width ?: LayoutParams.WRAP_CONTENT,
60
+ lp?.height ?: LayoutParams.WRAP_CONTENT
56
61
  )
57
62
  }
58
63
  }
@@ -61,15 +66,16 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
61
66
  return p is android.widget.LinearLayout.LayoutParams
62
67
  }
63
68
 
69
+ @SuppressLint("DrawAllocation")
64
70
  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
65
71
  val selfParams = this.layoutParams
66
- if (selfParams == null || selfParams !is android.widget.LinearLayout.LayoutParams) {
72
+ if (selfParams == null || selfParams !is LayoutParams) {
67
73
  val width = if (customViewWidth > 0) {
68
74
  customViewWidth
69
75
  } else if (selfParams != null && selfParams.width > 0) {
70
76
  selfParams.width
71
77
  } else {
72
- android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
78
+ LayoutParams.WRAP_CONTENT
73
79
  }
74
80
 
75
81
  val height = if (customViewHeight > 0) {
@@ -77,19 +83,19 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
77
83
  } else if (selfParams != null && selfParams.height > 0) {
78
84
  selfParams.height
79
85
  } else {
80
- android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
86
+ LayoutParams.WRAP_CONTENT
81
87
  }
82
88
 
83
- this.layoutParams = android.widget.LinearLayout.LayoutParams(width, height)
89
+ this.layoutParams = LayoutParams(width, height)
84
90
  }
85
91
 
86
92
  for (i in 0 until childCount) {
87
93
  val child = getChildAt(i)
88
94
  val params = child.layoutParams
89
- if (params == null || params !is android.widget.LinearLayout.LayoutParams) {
90
- child.layoutParams = android.widget.LinearLayout.LayoutParams(
91
- params?.width ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
92
- params?.height ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
95
+ if (params == null || params !is LayoutParams) {
96
+ child.layoutParams = LayoutParams(
97
+ params?.width ?: LayoutParams.WRAP_CONTENT,
98
+ params?.height ?: LayoutParams.WRAP_CONTENT
93
99
  )
94
100
  }
95
101
  }
@@ -142,7 +148,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
142
148
  pendingPosition = null
143
149
  }
144
150
 
145
- if (childCount > 0 && marker != null) {
151
+ if (isNotEmpty() && marker != null) {
146
152
  mainHandler.postDelayed({
147
153
  updateMarkerIcon()
148
154
  }, 100)
@@ -166,7 +172,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
166
172
  pendingLongitude?.let { lng ->
167
173
  updatePosition(lat, lng)
168
174
  }
169
- } catch (e: Exception) {
175
+ } catch (_: Exception) {
170
176
  // 忽略异常
171
177
  }
172
178
  }
@@ -184,7 +190,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
184
190
  pendingLatitude?.let { lat ->
185
191
  updatePosition(lat, lng)
186
192
  }
187
- } catch (e: Exception) {
193
+ } catch (_: Exception) {
188
194
  // 忽略异常
189
195
  }
190
196
  }
@@ -211,33 +217,12 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
211
217
  pendingPosition = latLng
212
218
  }
213
219
  }
214
- } catch (e: Exception) {
215
- // 忽略异常
216
- }
217
- }
218
-
219
- /**
220
- * 设置标记位置(兼容旧的 API)
221
- */
222
- fun setPosition(position: Map<String, Double>) {
223
- try {
224
- val lat = position["latitude"]
225
- val lng = position["longitude"]
226
-
227
- if (lat == null || lng == null) {
228
- return
229
- }
230
-
231
- if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
232
- return
233
- }
234
-
235
- updatePosition(lat, lng)
236
- } catch (e: Exception) {
220
+ } catch (_: Exception) {
237
221
  // 忽略异常
238
222
  }
239
223
  }
240
224
 
225
+
241
226
  /**
242
227
  * 设置标题
243
228
  */
@@ -274,19 +259,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
274
259
  marker?.let { it.isDraggable = draggable }
275
260
  }
276
261
 
277
- /**
278
- * 设置是否显示信息窗口
279
- */
280
- fun setShowsInfoWindow(show: Boolean) {
281
- marker?.let {
282
- if (show) {
283
- it.showInfoWindow()
284
- } else {
285
- it.hideInfoWindow()
286
- }
287
- }
288
- }
289
-
262
+
290
263
  /**
291
264
  * 设置透明度
292
265
  */
@@ -294,14 +267,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
294
267
  pendingOpacity = opacity
295
268
  marker?.let { it.alpha = opacity }
296
269
  }
297
-
298
- /**
299
- * 设置旋转角度
300
- */
301
- fun setMarkerRotation(rotation: Float) {
302
- marker?.let { it.rotateAngle = rotation }
303
- }
304
-
270
+
305
271
  /**
306
272
  * 设置锚点
307
273
  */
@@ -385,7 +351,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
385
351
  }
386
352
  }
387
353
  }
388
- } catch (e: Exception) {
354
+ } catch (_: Exception) {
389
355
  marker.setIcon(BitmapDescriptorFactory.defaultMarker())
390
356
  }
391
357
  }
@@ -412,7 +378,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
412
378
  } else {
413
379
  callback(null)
414
380
  }
415
- } catch (e: Exception) {
381
+ } catch (_: Exception) {
416
382
  callback(null)
417
383
  } finally {
418
384
  inputStream?.close()
@@ -432,7 +398,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
432
398
  return if (bitmap.width == finalWidth && bitmap.height == finalHeight) {
433
399
  bitmap
434
400
  } else {
435
- Bitmap.createScaledBitmap(bitmap, finalWidth, finalHeight, true)
401
+ bitmap.scale(finalWidth, finalHeight)
436
402
  }
437
403
  }
438
404
 
@@ -442,7 +408,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
442
408
  fun setPinColor(color: String?) {
443
409
  pendingPinColor = color
444
410
  // 颜色变化时需要重新创建 marker
445
- aMap?.let { map ->
411
+ aMap?.let { _ ->
446
412
  marker?.let { oldMarker ->
447
413
  val position = oldMarker.position
448
414
  oldMarker.remove()
@@ -473,7 +439,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
473
439
  else -> BitmapDescriptorFactory.HUE_RED
474
440
  }
475
441
  marker.setIcon(BitmapDescriptorFactory.defaultMarker(hue))
476
- } catch (e: Exception) {
442
+ } catch (_: Exception) {
477
443
  // 忽略异常
478
444
  }
479
445
  }
@@ -543,8 +509,9 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
543
509
  "latitude" to marker.position.latitude,
544
510
  "longitude" to marker.position.longitude
545
511
  ))
546
- // 显示信息窗口(如果有 title 或 snippet
547
- if (!marker.title.isNullOrEmpty() || !marker.snippet.isNullOrEmpty()) {
512
+ // 只有在没有自定义内容(children)且有 title 或 snippet 时才显示信息窗口
513
+ // 如果有自定义内容,说明用户已经自定义了显示内容,不需要默认信息窗口
514
+ if (view.isEmpty() && (!marker.title.isNullOrEmpty() || !marker.snippet.isNullOrEmpty())) {
548
515
  marker.showInfoWindow()
549
516
  }
550
517
  return true
@@ -553,30 +520,24 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
553
520
  }
554
521
 
555
522
  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
523
+ markerViewMap[marker]?.onMarkerDragStart(mapOf(
524
+ "latitude" to marker.position.latitude,
525
+ "longitude" to marker.position.longitude
560
526
  ))
561
- }
562
527
  }
563
528
 
564
529
  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
530
+ markerViewMap[marker]?.onMarkerDrag(mapOf(
531
+ "latitude" to marker.position.latitude,
532
+ "longitude" to marker.position.longitude
569
533
  ))
570
- }
571
534
  }
572
535
 
573
536
  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
537
+ markerViewMap[marker]?.onMarkerDragEnd(mapOf(
538
+ "latitude" to marker.position.latitude,
539
+ "longitude" to marker.position.longitude
578
540
  ))
579
- }
580
541
  }
581
542
  }
582
543
 
@@ -603,7 +564,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
603
564
  pendingAnchor?.let { m.setAnchor(it.first, it.second) }
604
565
 
605
566
  // 优先级:children > icon > pinColor
606
- if (childCount == 0) {
567
+ if (isEmpty()) {
607
568
  if (pendingIconUri != null) {
608
569
  loadAndSetIcon(pendingIconUri!!, m)
609
570
  } else if (pendingPinColor != null) {
@@ -621,11 +582,11 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
621
582
  private fun createDefaultMarkerBitmap(): Bitmap {
622
583
  val width = 48
623
584
  val height = 72
624
- val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
585
+ val bitmap = createBitmap(width, height)
625
586
  val canvas = Canvas(bitmap)
626
587
 
627
588
  val paint = Paint(Paint.ANTI_ALIAS_FLAG)
628
- paint.color = Color.parseColor("#FF5252")
589
+ paint.color = "#FF5252".toColorInt()
629
590
  paint.style = Paint.Style.FILL
630
591
 
631
592
  // 绘制圆形顶部
@@ -652,7 +613,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
652
613
  * 将视图转换为 Bitmap
653
614
  */
654
615
  private fun createBitmapFromView(): Bitmap? {
655
- if (childCount == 0) return null
616
+ if (isEmpty()) return null
656
617
 
657
618
  return try {
658
619
  val childView = getChildAt(0)
@@ -661,10 +622,8 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
661
622
 
662
623
  val finalWidth = if (measuredWidth > 0) measuredWidth else (if (customViewWidth > 0) customViewWidth else 240)
663
624
  val finalHeight = if (measuredHeight > 0) measuredHeight else (if (customViewHeight > 0) customViewHeight else 80)
664
-
665
- if (finalWidth <= 0 || finalHeight <= 0) return null
666
-
667
- if (measuredWidth != finalWidth || measuredHeight != finalHeight) {
625
+
626
+ if (measuredWidth != finalWidth || measuredHeight != finalHeight) {
668
627
  childView.measure(
669
628
  MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
670
629
  MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY)
@@ -672,13 +631,13 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
672
631
  childView.layout(0, 0, finalWidth, finalHeight)
673
632
  }
674
633
 
675
- val bitmap = Bitmap.createBitmap(finalWidth, finalHeight, Bitmap.Config.ARGB_8888)
634
+ val bitmap = createBitmap(finalWidth, finalHeight)
676
635
  val canvas = Canvas(bitmap)
677
- canvas.drawColor(android.graphics.Color.TRANSPARENT)
636
+ canvas.drawColor(Color.TRANSPARENT)
678
637
  childView.draw(canvas)
679
638
 
680
639
  bitmap
681
- } catch (e: Exception) {
640
+ } catch (_: Exception) {
682
641
  null
683
642
  }
684
643
  }
@@ -710,7 +669,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
710
669
  * 更新 marker 图标
711
670
  */
712
671
  private fun updateMarkerIcon() {
713
- if (childCount > 0) {
672
+ if (isNotEmpty()) {
714
673
  val customBitmap = createBitmapFromView()
715
674
  customBitmap?.let {
716
675
  marker?.setIcon(BitmapDescriptorFactory.fromBitmap(it))
@@ -727,25 +686,25 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
727
686
 
728
687
  override fun removeView(child: View?) {
729
688
  try {
730
- if (child != null && indexOfChild(child) >= 0) {
689
+ if (child != null && contains(child)) {
731
690
  super.removeView(child)
732
691
  // 不要在这里恢复默认图标
733
692
  // 如果 MarkerView 整体要被移除,onDetachedFromWindow 会处理
734
693
  // 如果只是移除 children 并保留 Marker,应该由外部重新设置 children
735
694
  }
736
- } catch (e: Exception) {
695
+ } catch (_: Exception) {
737
696
  // 忽略异常
738
697
  }
739
698
  }
740
699
 
741
700
  override fun removeViewAt(index: Int) {
742
701
  try {
743
- if (index >= 0 && index < childCount) {
702
+ if (index in 0..<childCount) {
744
703
  super.removeViewAt(index)
745
704
  // 只在还有子视图时更新图标
746
705
  if (!isRemoving && childCount > 1 && marker != null) {
747
706
  mainHandler.postDelayed({
748
- if (!isRemoving && marker != null && childCount > 0) {
707
+ if (!isRemoving && marker != null && isNotEmpty()) {
749
708
  updateMarkerIcon()
750
709
  }
751
710
  }, 50)
@@ -753,7 +712,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
753
712
  // 如果最后一个子视图被移除,什么都不做
754
713
  // 让 onDetachedFromWindow 处理完整的清理
755
714
  }
756
- } catch (e: Exception) {
715
+ } catch (_: Exception) {
757
716
  // 忽略异常
758
717
  }
759
718
  }
@@ -765,8 +724,8 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
765
724
  for (i in 0 until view.childCount) {
766
725
  val child = view.getChildAt(i)
767
726
  val currentParams = child.layoutParams
768
- if (currentParams != null && currentParams !is android.widget.LinearLayout.LayoutParams) {
769
- child.layoutParams = android.widget.LinearLayout.LayoutParams(
727
+ if (currentParams != null && currentParams !is LayoutParams) {
728
+ child.layoutParams = LayoutParams(
770
729
  currentParams.width,
771
730
  currentParams.height
772
731
  )
@@ -781,19 +740,19 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
781
740
  // 🔑 关键修复:记录添加前的子视图数量
782
741
  val childCountBefore = childCount
783
742
 
784
- val finalParams = android.widget.LinearLayout.LayoutParams(
785
- if (customViewWidth > 0) customViewWidth else android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
786
- if (customViewHeight > 0) customViewHeight else android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
743
+ val finalParams = LayoutParams(
744
+ if (customViewWidth > 0) customViewWidth else LayoutParams.WRAP_CONTENT,
745
+ if (customViewHeight > 0) customViewHeight else LayoutParams.WRAP_CONTENT
787
746
  )
788
747
 
789
748
  super.addView(child, index, finalParams)
790
749
 
791
750
  child?.let {
792
751
  val childParams = it.layoutParams
793
- if (childParams !is android.widget.LinearLayout.LayoutParams) {
794
- it.layoutParams = android.widget.LinearLayout.LayoutParams(
795
- childParams?.width ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
796
- childParams?.height ?: android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
752
+ if (childParams !is LayoutParams) {
753
+ it.layoutParams = LayoutParams(
754
+ childParams?.width ?: LayoutParams.WRAP_CONTENT,
755
+ childParams?.height ?: LayoutParams.WRAP_CONTENT
797
756
  )
798
757
  }
799
758
  fixChildLayoutParams(it)
@@ -819,7 +778,7 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
819
778
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
820
779
  super.onLayout(changed, left, top, right, bottom)
821
780
  // 🔑 关键修复:只有在有子视图且 marker 存在时才更新,避免不必要的刷新
822
- if (changed && !isRemoving && childCount > 0 && marker != null) {
781
+ if (changed && !isRemoving && isNotEmpty() && marker != null) {
823
782
  mainHandler.postDelayed({
824
783
  if (!isRemoving && marker != null) {
825
784
  updateMarkerIcon()
@@ -842,14 +801,19 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
842
801
  override fun onDetachedFromWindow() {
843
802
  super.onDetachedFromWindow()
844
803
 
845
- // 标记正在移除
846
- isRemoving = true
847
-
804
+ // 🔑 关键修复:使用 post 延迟检查
848
805
  // 清理所有延迟任务
849
806
  mainHandler.removeCallbacksAndMessages(null)
850
807
 
851
- // 移除 marker
852
- removeMarker()
808
+ // 延迟检查 parent 状态
809
+ mainHandler.post {
810
+ if (parent == null) {
811
+ // 标记正在移除
812
+ isRemoving = true
813
+ // 移除 marker
814
+ removeMarker()
815
+ }
816
+ }
853
817
  }
854
818
  }
855
819
 
@@ -9,13 +9,12 @@ import com.amap.api.maps.model.MultiPointItem
9
9
  import com.amap.api.maps.model.MultiPointOverlay
10
10
  import com.amap.api.maps.model.MultiPointOverlayOptions
11
11
  import expo.modules.kotlin.AppContext
12
- import expo.modules.kotlin.viewevent.EventDispatcher
12
+
13
13
  import expo.modules.kotlin.views.ExpoView
14
14
 
15
15
  class MultiPointView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
16
16
 
17
- private val onPress by EventDispatcher()
18
-
17
+
19
18
  private var multiPointOverlay: MultiPointOverlay? = null
20
19
  private var aMap: AMap? = null
21
20
  private var points: MutableList<MultiPointItem> = mutableListOf()
@@ -52,6 +51,7 @@ class MultiPointView(context: Context, appContext: AppContext) : ExpoView(contex
52
51
  * 设置图标
53
52
  */
54
53
  fun setIcon(iconUri: String?) {
54
+
55
55
  // 简化处理,实际需要实现图片加载
56
56
  createOrUpdateMultiPoint()
57
57
  }
@@ -100,7 +100,12 @@ class MultiPointView(context: Context, appContext: AppContext) : ExpoView(contex
100
100
 
101
101
  override fun onDetachedFromWindow() {
102
102
  super.onDetachedFromWindow()
103
- removeMultiPoint()
104
- aMap = null
103
+ // 🔑 关键修复:使用 post 延迟检查
104
+ post {
105
+ if (parent == null) {
106
+ removeMultiPoint()
107
+ aMap = null
108
+ }
109
+ }
105
110
  }
106
111
  }
@@ -16,6 +16,14 @@ class MultiPointViewModule : Module() {
16
16
  Prop<List<Map<String, Any>>>("points") { view: MultiPointView, points ->
17
17
  view.setPoints(points)
18
18
  }
19
+
20
+ Prop<String>("icon") { view: MultiPointView, icon ->
21
+ view.setIcon(icon)
22
+ }
23
+
24
+ Prop<Map<String, Float>>("anchor"){ view: MultiPointView, anchor ->
25
+ view.setAnchor(anchor)
26
+ }
19
27
  }
20
28
  }
21
29
  }
@@ -142,7 +142,12 @@ class PolygonView(context: Context, appContext: AppContext) : ExpoView(context,
142
142
 
143
143
  override fun onDetachedFromWindow() {
144
144
  super.onDetachedFromWindow()
145
- removePolygon()
146
- aMap = null
145
+ // 🔑 关键修复:使用 post 延迟检查
146
+ post {
147
+ if (parent == null) {
148
+ removePolygon()
149
+ aMap = null
150
+ }
151
+ }
147
152
  }
148
153
  }
@@ -261,7 +261,12 @@ class PolylineView(context: Context, appContext: AppContext) : ExpoView(context,
261
261
 
262
262
  override fun onDetachedFromWindow() {
263
263
  super.onDetachedFromWindow()
264
- removePolyline()
265
- aMap = null
264
+ // 🔑 关键修复:使用 post 延迟检查
265
+ post {
266
+ if (parent == null) {
267
+ removePolyline()
268
+ aMap = null
269
+ }
270
+ }
266
271
  }
267
272
  }
@@ -3,7 +3,6 @@ package expo.modules.gaodemap.services
3
3
  import android.app.Notification
4
4
  import android.app.NotificationChannel
5
5
  import android.app.NotificationManager
6
- import android.app.PendingIntent
7
6
  import android.app.Service
8
7
  import android.content.Context
9
8
  import android.content.Intent
@@ -60,7 +59,7 @@ class LocationForegroundService : Service() {
60
59
  setShowBadge(false)
61
60
  }
62
61
 
63
- val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
62
+ val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
64
63
  manager.createNotificationChannel(channel)
65
64
  }
66
65
  }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.gaodemap.utils
2
2
 
3
3
  import android.graphics.Color
4
+ import androidx.core.graphics.toColorInt
4
5
 
5
6
  object ColorParser {
6
7
  /**
@@ -22,12 +23,12 @@ object ColorParser {
22
23
  private fun parseColorString(color: String): Int {
23
24
  return try {
24
25
  when {
25
- color.startsWith("#") -> Color.parseColor(color)
26
+ color.startsWith("#") -> color.toColorInt()
26
27
  color.startsWith("rgba(") -> parseRgbaColor(color)
27
28
  color.startsWith("rgb(") -> parseRgbColor(color)
28
29
  else -> getNamedColor(color)
29
30
  }
30
- } catch (e: Exception) {
31
+ } catch (_: Exception) {
31
32
  Color.BLACK
32
33
  }
33
34
  }
package/docs/API.md CHANGED
@@ -264,12 +264,12 @@ ExpoGaodeMapModule.setDesiredAccuracy(3); // iOS 精度级别
264
264
  import { ExpoGaodeMapModule } from 'expo-gaode-map';
265
265
 
266
266
  // 监听位置更新
267
- const locationSubscription = ExpoGaodeMapModule.addListener('onLocationUpdate', (location) => {
267
+ const locationSubscription = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (location) => {
268
268
  console.log('位置更新:', location);
269
269
  });
270
270
 
271
271
  // 监听方向更新(iOS)
272
- const headingSubscription = ExpoGaodeMapModule.addListener('onHeadingUpdate', (heading) => {
272
+ const headingSubscription = ExpoGaodeMapModule.onHeadingUpdate('onHeadingUpdate', (heading) => {
273
273
  console.log('方向更新:', heading);
274
274
  });
275
275
 
package/docs/EXAMPLES.md CHANGED
@@ -286,7 +286,7 @@ export default function LocationApp() {
286
286
  ExpoGaodeMapModule.setInterval(2000);
287
287
 
288
288
  // 监听位置更新
289
- const subscription = ExpoGaodeMapModule.addListener('onLocationUpdate', (loc) => {
289
+ const subscription = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (loc) => {
290
290
  console.log('位置更新:', loc);
291
291
  setLocation(loc);
292
292
  });
@@ -914,7 +914,7 @@ ExpoGaodeMapModule.startUpdatingHeading();
914
914
  ExpoGaodeMapModule.stopUpdatingHeading();
915
915
 
916
916
  // 监听方向更新
917
- const subscription = ExpoGaodeMapModule.addListener('onHeadingUpdate', (heading) => {
917
+ const subscription = ExpoGaodeMapModule.onHeadingUpdate('onHeadingUpdate', (heading) => {
918
918
  console.log('方向更新:', heading);
919
919
  });
920
920
 
package/docs/MIGRATION.md CHANGED
@@ -159,7 +159,7 @@ subscription.remove();
159
159
  ```typescript
160
160
  import { ExpoGaodeMapModule } from 'expo-gaode-map';
161
161
 
162
- const subscription = ExpoGaodeMapModule.addListener('onLocationUpdate', (location) => {
162
+ const subscription = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (location) => {
163
163
  console.log('位置更新:', location);
164
164
  });
165
165
 
@@ -304,7 +304,7 @@ export default function App() {
304
304
  ExpoGaodeMapModule.setInterval(2000);
305
305
 
306
306
  // 监听
307
- const sub = ExpoGaodeMapModule.addListener('onLocationUpdate', (loc) => {
307
+ const sub = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (loc) => {
308
308
  setLocation(loc);
309
309
  });
310
310
 
@@ -340,7 +340,7 @@ export default function App() {
340
340
  | `checkLocationPermission()` | `ExpoGaodeMapModule.checkLocationPermission()` | 检查权限 |
341
341
  | `requestLocationPermission()` | `ExpoGaodeMapModule.requestLocationPermission()` | 请求权限 |
342
342
  | `configure(options)` | 使用单独的配置方法 | 见下方详细说明 |
343
- | `addLocationListener()` | `ExpoGaodeMapModule.addListener('onLocationUpdate', ...)` | 位置监听 |
343
+ | `addLocationListener()` | `ExpoGaodeMapModule.addLocationListener('onLocationUpdate', ...)` | 位置监听 |
344
344
  | `coordinateConvert()` | `ExpoGaodeMapModule.coordinateConvert()` | 坐标转换 |
345
345
  | `startUpdatingHeading()` | `ExpoGaodeMapModule.startUpdatingHeading()` | 开始方向更新 |
346
346
  | `stopUpdatingHeading()` | `ExpoGaodeMapModule.stopUpdatingHeading()` | 停止方向更新 |
@@ -192,7 +192,8 @@ class MarkerView: ExpoView {
192
192
  }
193
193
 
194
194
  annotationView?.annotation = annotation
195
- annotationView?.canShowCallout = canShowCallout
195
+ // 🔑 关键修复:有自定义内容时不显示默认 callout(信息窗口)
196
+ annotationView?.canShowCallout = false
196
197
  annotationView?.isDraggable = draggable
197
198
  self.annotationView = annotationView
198
199
 
@@ -231,6 +232,7 @@ class MarkerView: ExpoView {
231
232
  }
232
233
 
233
234
  annotationView?.annotation = annotation
235
+ // 只有在没有自定义内容时才使用 canShowCallout 设置
234
236
  annotationView?.canShowCallout = canShowCallout
235
237
  annotationView?.isDraggable = draggable
236
238
  self.annotationView = annotationView
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "2.0.0-alpha.3",
3
+ "version": "2.0.0-alpha.4",
4
4
  "description": "一个功能完整的高德地图 React Native 组件库,基于 Expo Modules 开发,提供地图显示、定位、覆盖物等功能。",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",