expo-gaode-map 1.0.8 → 1.1.0

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.
Files changed (34) hide show
  1. package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +24 -6
  2. package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +6 -2
  3. package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +6 -3
  4. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +373 -31
  5. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +30 -9
  6. package/android/src/main/java/expo/modules/gaodemap/utils/ColorParser.kt +25 -0
  7. package/build/components/overlays/Circle.d.ts +2 -1
  8. package/build/components/overlays/Circle.d.ts.map +1 -1
  9. package/build/components/overlays/Circle.js +39 -0
  10. package/build/components/overlays/Circle.js.map +1 -1
  11. package/build/components/overlays/Marker.js +19 -3
  12. package/build/components/overlays/Marker.js.map +1 -1
  13. package/build/types/location.types.d.ts +4 -0
  14. package/build/types/location.types.d.ts.map +1 -1
  15. package/build/types/location.types.js.map +1 -1
  16. package/build/types/overlays.types.d.ts +20 -1
  17. package/build/types/overlays.types.d.ts.map +1 -1
  18. package/build/types/overlays.types.js.map +1 -1
  19. package/docs/API.en.md +14 -4
  20. package/docs/API.md +52 -4
  21. package/docs/EXAMPLES.en.md +58 -1
  22. package/docs/EXAMPLES.md +208 -1
  23. package/ios/ExpoGaodeMapView.swift +17 -0
  24. package/ios/overlays/CircleViewModule.swift +0 -2
  25. package/ios/overlays/MarkerView.swift +224 -28
  26. package/ios/overlays/MarkerViewModule.swift +15 -2
  27. package/ios/overlays/PolygonViewModule.swift +0 -2
  28. package/ios/overlays/PolylineViewModule.swift +0 -2
  29. package/ios/utils/ColorParser.swift +45 -0
  30. package/package.json +3 -2
  31. package/src/components/overlays/Circle.tsx +48 -0
  32. package/src/components/overlays/Marker.tsx +29 -8
  33. package/src/types/location.types.ts +5 -0
  34. package/src/types/overlays.types.ts +23 -1
@@ -65,12 +65,15 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
65
65
  val lng = center["longitude"] ?: 0.0
66
66
  val latLng = LatLng(lat, lng)
67
67
 
68
+ // 将 dp 转换为 px,与 iOS 的 points 对应
69
+ val density = context.resources.displayMetrics.density
70
+
68
71
  val options = com.amap.api.maps.model.CircleOptions()
69
72
  .center(latLng)
70
73
  .radius(radius)
71
74
  .fillColor(fillColor)
72
75
  .strokeColor(strokeColor)
73
- .strokeWidth(strokeWidth)
76
+ .strokeWidth(strokeWidth * density)
74
77
 
75
78
  val circle = aMap.addCircle(options)
76
79
  circles[id] = circle
@@ -104,7 +107,10 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
104
107
  radius?.let { circle.radius = it }
105
108
  fillColor?.let { circle.fillColor = it }
106
109
  strokeColor?.let { circle.strokeColor = it }
107
- strokeWidth?.let { circle.strokeWidth = it }
110
+ strokeWidth?.let {
111
+ val density = context.resources.displayMetrics.density
112
+ circle.strokeWidth = it * density
113
+ }
108
114
  }
109
115
  }
110
116
 
@@ -322,9 +328,12 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
322
328
  LatLng(lat, lng)
323
329
  }
324
330
 
331
+ // 将 dp 转换为 px,与 iOS 的 points 对应
332
+ val density = context.resources.displayMetrics.density
333
+
325
334
  val options = com.amap.api.maps.model.PolylineOptions()
326
335
  .addAll(latLngs)
327
- .width(width)
336
+ .width(width * density)
328
337
  .color(color)
329
338
 
330
339
  val polyline = aMap.addPolyline(options)
@@ -381,7 +390,10 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
381
390
  polyline.points = latLngs
382
391
  }
383
392
 
384
- width?.let { polyline.width = it }
393
+ width?.let {
394
+ val density = context.resources.displayMetrics.density
395
+ polyline.width = it * density
396
+ }
385
397
  color?.let { polyline.color = it }
386
398
  }
387
399
  }
@@ -405,11 +417,14 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
405
417
  LatLng(lat, lng)
406
418
  }
407
419
 
420
+ // 将 dp 转换为 px,与 iOS 的 points 对应
421
+ val density = context.resources.displayMetrics.density
422
+
408
423
  val options = com.amap.api.maps.model.PolygonOptions()
409
424
  .addAll(latLngs)
410
425
  .fillColor(fillColor)
411
426
  .strokeColor(strokeColor)
412
- .strokeWidth(strokeWidth)
427
+ .strokeWidth(strokeWidth * density)
413
428
  .zIndex(zIndex)
414
429
 
415
430
  val polygon = aMap.addPolygon(options)
@@ -448,7 +463,10 @@ class OverlayManager(private val aMap: AMap, private val context: Context) {
448
463
 
449
464
  fillColor?.let { polygon.fillColor = it }
450
465
  strokeColor?.let { polygon.strokeColor = it }
451
- strokeWidth?.let { polygon.strokeWidth = it }
466
+ strokeWidth?.let {
467
+ val density = context.resources.displayMetrics.density
468
+ polygon.strokeWidth = it * density
469
+ }
452
470
  zIndex?.let { polygon.zIndex = it }
453
471
  }
454
472
  }
@@ -142,8 +142,12 @@ class UIManager(private val aMap: AMap, private val context: Context) {
142
142
  }
143
143
 
144
144
  // 是否显示精度圈 (showsAccuracyRing)
145
- (config["showsAccuracyRing"] as? Boolean)?.let {
146
- style.showMyLocation(it)
145
+ (config["showsAccuracyRing"] as? Boolean)?.let { showRing ->
146
+ if (!showRing) {
147
+ // 不显示精度圈,但要显示蓝点
148
+ style.radiusFillColor(android.graphics.Color.TRANSPARENT)
149
+ style.strokeColor(android.graphics.Color.TRANSPARENT)
150
+ }
147
151
  }
148
152
 
149
153
  // 自定义图标 (image)
@@ -71,10 +71,12 @@ class CircleView(context: Context, appContext: AppContext) : ExpoView(context, a
71
71
 
72
72
  /**
73
73
  * 设置边框宽度
74
+ * 将 dp 转换为 px,与 iOS 的 points 对应
74
75
  */
75
76
  fun setStrokeWidth(width: Float) {
76
- strokeWidth = width
77
- circle?.strokeWidth = width
77
+ val density = context.resources.displayMetrics.density
78
+ strokeWidth = width * density
79
+ circle?.strokeWidth = strokeWidth
78
80
  }
79
81
 
80
82
  /**
@@ -92,13 +94,14 @@ class CircleView(context: Context, appContext: AppContext) : ExpoView(context, a
92
94
  val centerPoint = center ?: return
93
95
 
94
96
  if (circle == null) {
97
+ val density = context.resources.displayMetrics.density
95
98
  circle = map.addCircle(
96
99
  CircleOptions()
97
100
  .center(centerPoint)
98
101
  .radius(radius)
99
102
  .fillColor(fillColor)
100
103
  .strokeColor(strokeColor)
101
- .strokeWidth(strokeWidth)
104
+ .strokeWidth(strokeWidth * density)
102
105
  )
103
106
  }
104
107
  }
@@ -4,6 +4,11 @@ import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.graphics.Bitmap
6
6
  import android.graphics.Canvas
7
+ import android.graphics.Color
8
+ import android.graphics.Paint
9
+ import android.graphics.Path
10
+ import android.os.Handler
11
+ import android.os.Looper
7
12
  import android.view.View
8
13
  import com.amap.api.maps.AMap
9
14
  import com.amap.api.maps.model.BitmapDescriptorFactory
@@ -29,26 +34,152 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
29
34
 
30
35
  private var marker: Marker? = null
31
36
  private var aMap: AMap? = null
37
+ private var pendingPosition: LatLng? = null
38
+ private var pendingLatitude: Double? = null // 临时存储纬度
39
+ private var pendingLongitude: Double? = null // 临时存储经度
40
+ private var iconWidth: Int = 0 // 用于自定义图标的宽度
41
+ private var iconHeight: Int = 0 // 用于自定义图标的高度
42
+ private var customViewWidth: Int = 0 // 用于自定义视图(children)的宽度
43
+ private var customViewHeight: Int = 0 // 用于自定义视图(children)的高度
44
+ private val mainHandler = Handler(Looper.getMainLooper())
32
45
 
33
46
  /**
34
47
  * 设置地图实例
35
48
  */
36
49
  @Suppress("unused")
37
50
  fun setMap(map: AMap) {
51
+ android.util.Log.d("MarkerView", "🗺️ setMap 被调用,pendingPosition = $pendingPosition, childCount = $childCount")
38
52
  aMap = map
39
53
  createOrUpdateMarker()
54
+
55
+ // 如果之前已经设置了位置但没有 marker,现在设置位置
56
+ pendingPosition?.let { pos ->
57
+ android.util.Log.d("MarkerView", "✅ 应用待处理的位置: $pos")
58
+ marker?.position = pos
59
+ pendingPosition = null
60
+ }
61
+
62
+ // 如果已经有子视图,触发多次延迟更新确保内容渲染
63
+ if (childCount > 0 && marker != null) {
64
+ android.util.Log.d("MarkerView", "🎨 setMap 后触发延迟更新")
65
+
66
+ // 100ms 后第一次更新
67
+ mainHandler.postDelayed({
68
+ android.util.Log.d("MarkerView", "⏰ setMap 第一次延迟更新(100ms)")
69
+ updateMarkerIcon()
70
+ }, 100)
71
+
72
+ // 300ms 后第二次更新,确保 Text 内容已加载
73
+ mainHandler.postDelayed({
74
+ android.util.Log.d("MarkerView", "⏰ setMap 第二次延迟更新(300ms,确保内容加载)")
75
+ updateMarkerIcon()
76
+ }, 300)
77
+ }
78
+ }
79
+
80
+ /**
81
+ * 设置纬度
82
+ */
83
+ fun setLatitude(lat: Double) {
84
+ try {
85
+ // 验证坐标范围
86
+ if (lat < -90 || lat > 90) {
87
+ android.util.Log.e("MarkerView", "❌ 纬度超出有效范围: $lat")
88
+ return
89
+ }
90
+
91
+ android.util.Log.d("MarkerView", "📍 setLatitude: $lat")
92
+ pendingLatitude = lat
93
+
94
+ // 如果经度也已设置,则更新位置
95
+ pendingLongitude?.let { lng ->
96
+ updatePosition(lat, lng)
97
+ }
98
+ } catch (e: Exception) {
99
+ android.util.Log.e("MarkerView", "❌ setLatitude 发生异常", e)
100
+ }
101
+ }
102
+
103
+ /**
104
+ * 设置经度
105
+ */
106
+ fun setLongitude(lng: Double) {
107
+ try {
108
+ // 验证坐标范围
109
+ if (lng < -180 || lng > 180) {
110
+ android.util.Log.e("MarkerView", "❌ 经度超出有效范围: $lng")
111
+ return
112
+ }
113
+
114
+ android.util.Log.d("MarkerView", "📍 setLongitude: $lng")
115
+ pendingLongitude = lng
116
+
117
+ // 如果纬度也已设置,则更新位置
118
+ pendingLatitude?.let { lat ->
119
+ updatePosition(lat, lng)
120
+ }
121
+ } catch (e: Exception) {
122
+ android.util.Log.e("MarkerView", "❌ setLongitude 发生异常", e)
123
+ }
124
+ }
125
+
126
+ /**
127
+ * 更新标记位置(当经纬度都设置后)
128
+ */
129
+ private fun updatePosition(lat: Double, lng: Double) {
130
+ try {
131
+ val latLng = LatLng(lat, lng)
132
+
133
+ android.util.Log.d("MarkerView", "📍 updatePosition: ($lat, $lng), marker = $marker, aMap = $aMap")
134
+
135
+ marker?.let {
136
+ android.util.Log.d("MarkerView", "✅ 更新现有 marker 位置")
137
+ it.position = latLng
138
+ pendingPosition = null
139
+ pendingLatitude = null
140
+ pendingLongitude = null
141
+ } ?: run {
142
+ android.util.Log.d("MarkerView", "❌ marker 为 null")
143
+ if (aMap != null) {
144
+ android.util.Log.d("MarkerView", "🔧 aMap 存在,创建新 marker")
145
+ createOrUpdateMarker()
146
+ marker?.position = latLng
147
+ pendingLatitude = null
148
+ pendingLongitude = null
149
+ } else {
150
+ android.util.Log.d("MarkerView", "⏳ aMap 为 null,保存位置等待 setMap")
151
+ pendingPosition = latLng
152
+ }
153
+ }
154
+ } catch (e: Exception) {
155
+ android.util.Log.e("MarkerView", "❌ updatePosition 发生异常", e)
156
+ }
40
157
  }
41
158
 
42
159
  /**
43
- * 设置标记位置
160
+ * 设置标记位置(兼容旧的 API)
44
161
  */
45
162
  fun setPosition(position: Map<String, Double>) {
46
- val lat = position["latitude"] ?: return
47
- val lng = position["longitude"] ?: return
48
-
49
- marker?.let {
50
- it.position = LatLng(lat, lng)
51
- } ?: createOrUpdateMarker()
163
+ try {
164
+ val lat = position["latitude"]
165
+ val lng = position["longitude"]
166
+
167
+ // 验证坐标有效性
168
+ if (lat == null || lng == null) {
169
+ android.util.Log.e("MarkerView", "❌ 无效的位置数据: latitude=$lat, longitude=$lng")
170
+ return
171
+ }
172
+
173
+ // 验证坐标范围
174
+ if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
175
+ android.util.Log.e("MarkerView", "❌ 坐标超出有效范围: ($lat, $lng)")
176
+ return
177
+ }
178
+
179
+ updatePosition(lat, lng)
180
+ } catch (e: Exception) {
181
+ android.util.Log.e("MarkerView", "❌ setPosition 发生异常", e)
182
+ }
52
183
  }
53
184
 
54
185
  /**
@@ -139,24 +270,52 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
139
270
  marker?.let { it.zIndex = zIndex }
140
271
  }
141
272
 
273
+ /**
274
+ * 设置图标宽度(用于自定义图标 icon 属性)
275
+ */
276
+ fun setIconWidth(width: Int) {
277
+ iconWidth = width
278
+ android.util.Log.d("MarkerView", "📏 设置 iconWidth: $width")
279
+ }
280
+
281
+ /**
282
+ * 设置图标高度(用于自定义图标 icon 属性)
283
+ */
284
+ fun setIconHeight(height: Int) {
285
+ iconHeight = height
286
+ android.util.Log.d("MarkerView", "📏 设置 iconHeight: $height")
287
+ }
288
+
289
+ /**
290
+ * 设置自定义视图宽度(用于 children 属性)
291
+ */
292
+ fun setCustomViewWidth(width: Int) {
293
+ customViewWidth = width
294
+ android.util.Log.d("MarkerView", "📏 设置 customViewWidth: $width")
295
+ }
296
+
297
+ /**
298
+ * 设置自定义视图高度(用于 children 属性)
299
+ */
300
+ fun setCustomViewHeight(height: Int) {
301
+ customViewHeight = height
302
+ android.util.Log.d("MarkerView", "📏 设置 customViewHeight: $height")
303
+ }
304
+
142
305
  /**
143
306
  * 创建或更新标记
144
307
  */
145
308
  private fun createOrUpdateMarker() {
146
309
  aMap?.let { map ->
147
310
  if (marker == null) {
311
+ android.util.Log.d("MarkerView", "🔧 创建新的 marker")
148
312
  val options = MarkerOptions()
149
313
  marker = map.addMarker(options)
150
314
 
151
- // 延迟处理子视图,等待 React Native 添加完成
152
- postDelayed({
153
- if (childCount > 0) {
154
- val bitmap = createBitmapFromView()
155
- bitmap?.let {
156
- marker?.setIcon(BitmapDescriptorFactory.fromBitmap(it))
157
- }
158
- }
159
- }, 100)
315
+ android.util.Log.d("MarkerView", "📌 Marker 已添加到地图,childCount = $childCount")
316
+
317
+ // 不立即更新图标,等待延迟更新(在 addView onLayout 中)
318
+ android.util.Log.d("MarkerView", "⏳ 等待延迟更新图标")
160
319
 
161
320
  // 设置点击监听
162
321
  map.setOnMarkerClickListener { clickedMarker ->
@@ -210,40 +369,222 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
210
369
  }
211
370
  }
212
371
 
372
+ /**
373
+ * 创建默认 marker 图标 (红色大头针)
374
+ */
375
+ private fun createDefaultMarkerBitmap(): Bitmap {
376
+ val width = 48
377
+ val height = 72
378
+ val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
379
+ val canvas = Canvas(bitmap)
380
+
381
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG)
382
+ paint.color = Color.parseColor("#FF5252")
383
+ paint.style = Paint.Style.FILL
384
+
385
+ // 绘制圆形顶部
386
+ canvas.drawCircle(width / 2f, width / 2f, width / 2f - 2, paint)
387
+
388
+ // 绘制尖端
389
+ val path = Path()
390
+ path.moveTo(width / 2f, height.toFloat())
391
+ path.lineTo(width / 4f, width / 2f + 10f)
392
+ path.lineTo(3 * width / 4f, width / 2f + 10f)
393
+ path.close()
394
+ canvas.drawPath(path, paint)
395
+
396
+ // 绘制白色边框
397
+ paint.color = Color.WHITE
398
+ paint.style = Paint.Style.STROKE
399
+ paint.strokeWidth = 3f
400
+ canvas.drawCircle(width / 2f, width / 2f, width / 2f - 4, paint)
401
+
402
+ return bitmap
403
+ }
404
+
213
405
  /**
214
406
  * 将视图转换为 Bitmap
215
407
  */
216
408
  private fun createBitmapFromView(): Bitmap? {
217
- if (childCount == 0) return null
409
+ if (childCount == 0) {
410
+ android.util.Log.w("MarkerView", "❌ childCount = 0")
411
+ return null
412
+ }
218
413
 
219
414
  return try {
220
- measure(
221
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
222
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
223
- )
224
- layout(0, 0, measuredWidth, measuredHeight)
415
+ val childView = getChildAt(0)
416
+ android.util.Log.d("MarkerView", "📦 子视图: $childView")
417
+
418
+ // 获取视图实际测量的尺寸(React Native 已经布局好的)
419
+ val measuredWidth = childView.measuredWidth
420
+ val measuredHeight = childView.measuredHeight
421
+
422
+ android.util.Log.d("MarkerView", "📏 子视图测量尺寸: ${measuredWidth}x${measuredHeight}")
423
+
424
+ // 优先使用已测量的尺寸,其次使用 customViewWidth/customViewHeight(用于 children),最后使用默认值
425
+ // 注意:iconWidth/iconHeight 是用于自定义图标的,不用于 children
426
+ val finalWidth = if (measuredWidth > 0) measuredWidth else (if (customViewWidth > 0) customViewWidth else 240)
427
+ val finalHeight = if (measuredHeight > 0) measuredHeight else (if (customViewHeight > 0) customViewHeight else 80)
428
+
429
+ android.util.Log.d("MarkerView", "📏 最终使用尺寸: ${finalWidth}x${finalHeight} (customViewWidth=$customViewWidth, customViewHeight=$customViewHeight)")
225
430
 
226
- val bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
431
+ // 打印视图层次结构以调试
432
+ if (childView is android.view.ViewGroup) {
433
+ android.util.Log.d("MarkerView", "📦 子视图有 ${childView.childCount} 个子视图:")
434
+ for (i in 0 until childView.childCount) {
435
+ val child = childView.getChildAt(i)
436
+ android.util.Log.d("MarkerView", " └─ 子视图[$i]: ${child.javaClass.simpleName}, 可见性: ${child.visibility}")
437
+ if (child is android.widget.TextView) {
438
+ android.util.Log.d("MarkerView", " 文字: '${child.text}', 颜色: ${Integer.toHexString(child.currentTextColor)}, 大小: ${child.textSize}")
439
+ }
440
+ }
441
+ }
442
+
443
+ if (finalWidth <= 0 || finalHeight <= 0) {
444
+ android.util.Log.w("MarkerView", "❌ 最终尺寸无效: ${finalWidth}x${finalHeight}")
445
+ return null
446
+ }
447
+
448
+ // 如果需要重新测量(尺寸改变了)
449
+ if (measuredWidth != finalWidth || measuredHeight != finalHeight) {
450
+ childView.measure(
451
+ MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
452
+ MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY)
453
+ )
454
+ childView.layout(0, 0, finalWidth, finalHeight)
455
+ android.util.Log.d("MarkerView", "✅ 子视图已重新测量和布局")
456
+ }
457
+
458
+ // 创建 Bitmap
459
+ val bitmap = Bitmap.createBitmap(finalWidth, finalHeight, Bitmap.Config.ARGB_8888)
227
460
  val canvas = Canvas(bitmap)
228
- draw(canvas)
461
+
462
+ // 设置背景为透明
463
+ canvas.drawColor(android.graphics.Color.TRANSPARENT)
464
+
465
+ // 绘制视图及其所有子视图
466
+ childView.draw(canvas)
467
+ android.util.Log.d("MarkerView", "🎨 Bitmap 已绘制,尺寸: ${bitmap.width}x${bitmap.height}")
468
+
229
469
  bitmap
230
470
  } catch (e: Exception) {
471
+ android.util.Log.e("MarkerView", "❌ 创建 Bitmap 失败", e)
231
472
  e.printStackTrace()
232
473
  null
233
474
  }
234
475
  }
235
476
 
477
+ /**
478
+ * 创建组合 Bitmap:默认 marker + 自定义内容
479
+ */
480
+ private fun createCombinedBitmap(): Bitmap? {
481
+ android.util.Log.d("MarkerView", "🖼️ createCombinedBitmap 开始")
482
+ val customBitmap = createBitmapFromView()
483
+ if (customBitmap == null) {
484
+ android.util.Log.w("MarkerView", "❌ 自定义 Bitmap 为 null")
485
+ return null
486
+ }
487
+ android.util.Log.d("MarkerView", "✅ 自定义 Bitmap: ${customBitmap.width}x${customBitmap.height}")
488
+
489
+ val markerBitmap = createDefaultMarkerBitmap()
490
+ android.util.Log.d("MarkerView", "✅ 默认 Marker Bitmap: ${markerBitmap.width}x${markerBitmap.height}")
491
+
492
+ // 计算总尺寸:marker 在下,自定义内容在上
493
+ val totalWidth = maxOf(markerBitmap.width, customBitmap.width)
494
+ val totalHeight = markerBitmap.height + customBitmap.height + 10 // 10px 间距
495
+
496
+ android.util.Log.d("MarkerView", "📐 组合尺寸: ${totalWidth}x${totalHeight}")
497
+
498
+ val combinedBitmap = Bitmap.createBitmap(totalWidth, totalHeight, Bitmap.Config.ARGB_8888)
499
+ val canvas = Canvas(combinedBitmap)
500
+
501
+ // 绘制自定义内容在上方
502
+ val customX = (totalWidth - customBitmap.width) / 2f
503
+ canvas.drawBitmap(customBitmap, customX, 0f, null)
504
+ android.util.Log.d("MarkerView", "🎨 已绘制自定义内容在 ($customX, 0)")
505
+
506
+ // 绘制 marker 在下方
507
+ val markerX = (totalWidth - markerBitmap.width) / 2f
508
+ val markerY = customBitmap.height + 10f
509
+ canvas.drawBitmap(markerBitmap, markerX, markerY, null)
510
+ android.util.Log.d("MarkerView", "📍 已绘制 marker 在 ($markerX, $markerY)")
511
+
512
+ return combinedBitmap
513
+ }
514
+
515
+ /**
516
+ * 更新 marker 图标
517
+ */
518
+ private fun updateMarkerIcon() {
519
+ android.util.Log.d("MarkerView", "🔄 updateMarkerIcon 被调用,childCount = $childCount")
520
+
521
+ if (childCount > 0) {
522
+ android.util.Log.d("MarkerView", "🎨 开始创建自定义 Bitmap(仅自定义内容)")
523
+ val customBitmap = createBitmapFromView()
524
+ customBitmap?.let {
525
+ android.util.Log.d("MarkerView", "✅ 自定义 Bitmap 创建成功,尺寸: ${it.width}x${it.height}")
526
+
527
+ marker?.setIcon(BitmapDescriptorFactory.fromBitmap(it))
528
+
529
+ // 设置 anchor 为底部中心,让自定义内容底部对齐地图坐标点
530
+ val anchorX = 0.5f // 水平居中
531
+ val anchorY = 1.0f // 垂直底部
532
+ android.util.Log.d("MarkerView", "🎯 设置 marker anchor: ($anchorX, $anchorY)")
533
+ marker?.setAnchor(anchorX, anchorY)
534
+
535
+ android.util.Log.d("MarkerView", "🎯 图标已设置到 marker")
536
+ } ?: run {
537
+ android.util.Log.w("MarkerView", "❌ 自定义 Bitmap 创建失败")
538
+ marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
539
+ }
540
+ } else {
541
+ android.util.Log.d("MarkerView", "📍 没有子视图,使用默认图标")
542
+ marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
543
+ marker?.setAnchor(0.5f, 1.0f) // 默认 anchor
544
+ }
545
+ }
546
+
547
+
236
548
  override fun addView(child: View?, index: Int, params: android.view.ViewGroup.LayoutParams?) {
549
+ android.util.Log.d("MarkerView", "➕ addView 被调用,child = $child")
237
550
  super.addView(child, index, params)
238
551
 
239
- // 当添加子视图时,手动触发测量和布局
240
- post {
241
- if (childCount > 0) {
242
- val bitmap = createBitmapFromView()
243
- bitmap?.let {
244
- marker?.setIcon(BitmapDescriptorFactory.fromBitmap(it))
245
- }
552
+ // 延迟更新图标,等待 React Native 样式和内容渲染
553
+ android.util.Log.d("MarkerView", "✅ 子视图已添加,准备延迟更新,marker=${marker}")
554
+ mainHandler.postDelayed({
555
+ android.util.Log.d("MarkerView", "⏰ 第一次延迟更新图标,marker=${marker}")
556
+ if (marker != null) {
557
+ updateMarkerIcon()
558
+ } else {
559
+ android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过第一次更新")
246
560
  }
561
+ }, 50)
562
+
563
+ mainHandler.postDelayed({
564
+ android.util.Log.d("MarkerView", "⏰ 第二次延迟更新图标(确保内容加载),marker=${marker}")
565
+ if (marker != null) {
566
+ updateMarkerIcon()
567
+ } else {
568
+ android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过第二次更新")
569
+ }
570
+ }, 150)
571
+ }
572
+
573
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
574
+ super.onLayout(changed, left, top, right, bottom)
575
+ android.util.Log.d("MarkerView", "📐 onLayout: changed=$changed, bounds=(${left},${top},${right},${bottom}), marker=${marker}")
576
+
577
+ // 布局完成后再次尝试更新图标(确保样式已应用)
578
+ if (changed && childCount > 0) {
579
+ android.util.Log.d("MarkerView", "🔄 布局改变,延迟更新图标,marker=${marker}")
580
+ mainHandler.postDelayed({
581
+ android.util.Log.d("MarkerView", "⏰ onLayout 延迟更新执行,marker=${marker}")
582
+ if (marker != null) {
583
+ updateMarkerIcon()
584
+ } else {
585
+ android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过 onLayout 更新")
586
+ }
587
+ }, 200)
247
588
  }
248
589
  }
249
590
 
@@ -260,3 +601,4 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
260
601
  removeMarker()
261
602
  }
262
603
  }
604
+
@@ -13,37 +13,58 @@ class MarkerViewModule : Module() {
13
13
  View(MarkerView::class) {
14
14
  Events("onPress", "onDragStart", "onDrag", "onDragEnd")
15
15
 
16
- Prop<Map<String, Double>>("position") { view: MarkerView, position ->
17
- view.setPosition(position)
16
+ // 拆分 position 为两个独立属性以兼容 React Native 旧架构
17
+ Prop<Double>("latitude") { view, lat ->
18
+ view.setLatitude(lat)
18
19
  }
19
20
 
20
- Prop<String>("title") { view: MarkerView, title ->
21
+ Prop<Double>("longitude") { view, lng ->
22
+ view.setLongitude(lng)
23
+ }
24
+
25
+ Prop<String>("title") { view, title ->
21
26
  view.setTitle(title)
22
27
  }
23
28
 
24
- Prop<String>("description") { view: MarkerView, description ->
29
+ Prop<String>("description") { view, description ->
25
30
  view.setDescription(description)
26
31
  }
27
32
 
28
- Prop<Boolean>("draggable") { view: MarkerView, draggable ->
33
+ Prop<Boolean>("draggable") { view, draggable ->
29
34
  view.setDraggable(draggable)
30
35
  }
31
36
 
32
- Prop<Float>("opacity") { view: MarkerView, opacity ->
37
+ Prop<Float>("opacity") { view, opacity ->
33
38
  view.setOpacity(opacity)
34
39
  }
35
40
 
36
- Prop<Boolean>("flat") { view: MarkerView, flat ->
41
+ Prop<Boolean>("flat") { view, flat ->
37
42
  view.setFlat(flat)
38
43
  }
39
44
 
40
- Prop<Float>("zIndex") { view: MarkerView, zIndex ->
45
+ Prop<Float>("zIndex") { view, zIndex ->
41
46
  view.setZIndex(zIndex)
42
47
  }
43
48
 
44
- Prop<Map<String, Float>>("anchor") { view: MarkerView, anchor ->
49
+ Prop<Map<String, Float>>("anchor") { view, anchor ->
45
50
  view.setAnchor(anchor)
46
51
  }
52
+
53
+ Prop<Int>("iconWidth") { view, width ->
54
+ view.setIconWidth(width)
55
+ }
56
+
57
+ Prop<Int>("iconHeight") { view, height ->
58
+ view.setIconHeight(height)
59
+ }
60
+
61
+ Prop<Int>("customViewWidth") { view, width ->
62
+ view.setCustomViewWidth(width)
63
+ }
64
+
65
+ Prop<Int>("customViewHeight") { view, height ->
66
+ view.setCustomViewHeight(height)
67
+ }
47
68
  }
48
69
  }
49
70
  }