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.
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +24 -6
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +6 -2
- package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +6 -3
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +373 -31
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +30 -9
- package/android/src/main/java/expo/modules/gaodemap/utils/ColorParser.kt +25 -0
- package/build/components/overlays/Circle.d.ts +2 -1
- package/build/components/overlays/Circle.d.ts.map +1 -1
- package/build/components/overlays/Circle.js +39 -0
- package/build/components/overlays/Circle.js.map +1 -1
- package/build/components/overlays/Marker.js +19 -3
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/types/location.types.d.ts +4 -0
- package/build/types/location.types.d.ts.map +1 -1
- package/build/types/location.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +20 -1
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/docs/API.en.md +14 -4
- package/docs/API.md +52 -4
- package/docs/EXAMPLES.en.md +58 -1
- package/docs/EXAMPLES.md +208 -1
- package/ios/ExpoGaodeMapView.swift +17 -0
- package/ios/overlays/CircleViewModule.swift +0 -2
- package/ios/overlays/MarkerView.swift +224 -28
- package/ios/overlays/MarkerViewModule.swift +15 -2
- package/ios/overlays/PolygonViewModule.swift +0 -2
- package/ios/overlays/PolylineViewModule.swift +0 -2
- package/ios/utils/ColorParser.swift +45 -0
- package/package.json +3 -2
- package/src/components/overlays/Circle.tsx +48 -0
- package/src/components/overlays/Marker.tsx +29 -8
- package/src/types/location.types.ts +5 -0
- 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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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)
|
|
409
|
+
if (childCount == 0) {
|
|
410
|
+
android.util.Log.w("MarkerView", "❌ childCount = 0")
|
|
411
|
+
return null
|
|
412
|
+
}
|
|
218
413
|
|
|
219
414
|
return try {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
17
|
-
|
|
16
|
+
// 拆分 position 为两个独立属性以兼容 React Native 旧架构
|
|
17
|
+
Prop<Double>("latitude") { view, lat ->
|
|
18
|
+
view.setLatitude(lat)
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
Prop<
|
|
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
|
|
29
|
+
Prop<String>("description") { view, description ->
|
|
25
30
|
view.setDescription(description)
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
Prop<Boolean>("draggable") { view
|
|
33
|
+
Prop<Boolean>("draggable") { view, draggable ->
|
|
29
34
|
view.setDraggable(draggable)
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
Prop<Float>("opacity") { view
|
|
37
|
+
Prop<Float>("opacity") { view, opacity ->
|
|
33
38
|
view.setOpacity(opacity)
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
Prop<Boolean>("flat") { view
|
|
41
|
+
Prop<Boolean>("flat") { view, flat ->
|
|
37
42
|
view.setFlat(flat)
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
Prop<Float>("zIndex") { view
|
|
45
|
+
Prop<Float>("zIndex") { view, zIndex ->
|
|
41
46
|
view.setZIndex(zIndex)
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
Prop<Map<String, Float>>("anchor") { view
|
|
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
|
}
|