expo-gaode-map 1.0.7 → 1.0.9
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/ExpoGaodeMapView.kt +19 -3
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +1 -1
- package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +24 -6
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +28 -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 +317 -2
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +16 -0
- 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.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +46 -1
- 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/map-view.types.d.ts +2 -1
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.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 +36 -5
- package/ios/ExpoGaodeMapViewModule.swift +1 -1
- package/ios/managers/UIManager.swift +32 -4
- package/ios/overlays/CircleViewModule.swift +0 -2
- package/ios/overlays/MarkerView.swift +205 -7
- package/ios/overlays/MarkerViewModule.swift +8 -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 +68 -1
- package/src/types/location.types.ts +5 -0
- package/src/types/map-view.types.ts +2 -1
- package/src/types/overlays.types.ts +23 -1
|
@@ -46,6 +46,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
46
46
|
private val onMapPress by EventDispatcher()
|
|
47
47
|
private val onMapLongPress by EventDispatcher()
|
|
48
48
|
private val onLoad by EventDispatcher()
|
|
49
|
+
private val onLocation by EventDispatcher()
|
|
49
50
|
private val onMarkerPress by EventDispatcher()
|
|
50
51
|
private val onMarkerDragStart by EventDispatcher()
|
|
51
52
|
private val onMarkerDrag by EventDispatcher()
|
|
@@ -80,7 +81,17 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
80
81
|
|
|
81
82
|
// 初始化管理器
|
|
82
83
|
cameraManager = CameraManager(aMap)
|
|
83
|
-
uiManager = UIManager(aMap, context)
|
|
84
|
+
uiManager = UIManager(aMap, context).apply {
|
|
85
|
+
// 设置定位变化回调
|
|
86
|
+
onLocationChanged = { latitude, longitude, accuracy ->
|
|
87
|
+
this@ExpoGaodeMapView.onLocation(mapOf(
|
|
88
|
+
"latitude" to latitude,
|
|
89
|
+
"longitude" to longitude,
|
|
90
|
+
"accuracy" to accuracy.toDouble(),
|
|
91
|
+
"timestamp" to System.currentTimeMillis()
|
|
92
|
+
))
|
|
93
|
+
}
|
|
94
|
+
}
|
|
84
95
|
overlayManager = OverlayManager(aMap, context).apply {
|
|
85
96
|
onMarkerPress = { id, lat, lng ->
|
|
86
97
|
this@ExpoGaodeMapView.onMarkerPress(mapOf(
|
|
@@ -479,12 +490,17 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
|
|
|
479
490
|
* 添加子视图时自动连接到地图
|
|
480
491
|
*/
|
|
481
492
|
override fun addView(child: View?, index: Int) {
|
|
493
|
+
if (child is MarkerView) {
|
|
494
|
+
// 不添加到视图层级,只调用 setMap
|
|
495
|
+
child.setMap(aMap)
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
|
|
482
499
|
super.addView(child, index)
|
|
483
500
|
|
|
484
|
-
//
|
|
501
|
+
// 自动将地图实例传递给其他覆盖物子视图
|
|
485
502
|
child?.let {
|
|
486
503
|
when (it) {
|
|
487
|
-
is MarkerView -> it.setMap(aMap)
|
|
488
504
|
is PolylineView -> it.setMap(aMap)
|
|
489
505
|
is PolygonView -> it.setMap(aMap)
|
|
490
506
|
is CircleView -> it.setMap(aMap)
|
|
@@ -11,7 +11,7 @@ class ExpoGaodeMapViewModule : Module() {
|
|
|
11
11
|
Name("ExpoGaodeMapView")
|
|
12
12
|
|
|
13
13
|
View(ExpoGaodeMapView::class) {
|
|
14
|
-
Events("onMapPress", "onMapLongPress", "onLoad", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress", "onPolygonPress", "onPolylinePress")
|
|
14
|
+
Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onMarkerPress", "onMarkerDragStart", "onMarkerDrag", "onMarkerDragEnd", "onCirclePress", "onPolygonPress", "onPolylinePress")
|
|
15
15
|
|
|
16
16
|
Prop<Int>("mapType") { view, type ->
|
|
17
17
|
view.mapType = type
|
|
@@ -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
|
}
|
|
@@ -3,6 +3,7 @@ package expo.modules.gaodemap.managers
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.graphics.BitmapFactory
|
|
5
5
|
import com.amap.api.maps.AMap
|
|
6
|
+
import com.amap.api.maps.LocationSource
|
|
6
7
|
import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
7
8
|
import com.amap.api.maps.model.MyLocationStyle
|
|
8
9
|
import expo.modules.gaodemap.utils.ColorParser
|
|
@@ -15,6 +16,8 @@ import java.net.URL
|
|
|
15
16
|
*/
|
|
16
17
|
class UIManager(private val aMap: AMap, private val context: Context) {
|
|
17
18
|
|
|
19
|
+
var onLocationChanged: ((latitude: Double, longitude: Double, accuracy: Float) -> Unit)? = null
|
|
20
|
+
|
|
18
21
|
// ==================== 控件显示 ====================
|
|
19
22
|
|
|
20
23
|
/**
|
|
@@ -87,8 +90,27 @@ class UIManager(private val aMap: AMap, private val context: Context) {
|
|
|
87
90
|
}
|
|
88
91
|
currentLocationStyle?.myLocationType(locationType)
|
|
89
92
|
aMap.myLocationStyle = currentLocationStyle
|
|
93
|
+
|
|
94
|
+
// 设置定位监听
|
|
95
|
+
aMap.setLocationSource(object : LocationSource {
|
|
96
|
+
override fun activate(listener: LocationSource.OnLocationChangedListener?) {
|
|
97
|
+
// 高德地图会自动处理定位,我们只需要监听位置变化
|
|
98
|
+
}
|
|
99
|
+
override fun deactivate() {}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// 监听定位变化
|
|
103
|
+
aMap.setOnMyLocationChangeListener { location ->
|
|
104
|
+
onLocationChanged?.invoke(
|
|
105
|
+
location.latitude,
|
|
106
|
+
location.longitude,
|
|
107
|
+
location.accuracy
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
90
111
|
aMap.isMyLocationEnabled = true
|
|
91
112
|
} else {
|
|
113
|
+
aMap.setOnMyLocationChangeListener(null)
|
|
92
114
|
aMap.isMyLocationEnabled = false
|
|
93
115
|
}
|
|
94
116
|
}
|
|
@@ -120,8 +142,12 @@ class UIManager(private val aMap: AMap, private val context: Context) {
|
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
// 是否显示精度圈 (showsAccuracyRing)
|
|
123
|
-
(config["showsAccuracyRing"] as? Boolean)?.let {
|
|
124
|
-
|
|
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
|
+
}
|
|
125
151
|
}
|
|
126
152
|
|
|
127
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
|
|
@@ -16,6 +21,12 @@ import expo.modules.kotlin.views.ExpoView
|
|
|
16
21
|
|
|
17
22
|
class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
18
23
|
|
|
24
|
+
init {
|
|
25
|
+
// 不可交互,通过父视图定位到屏幕外
|
|
26
|
+
isClickable = false
|
|
27
|
+
isFocusable = false
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
private val onPress by EventDispatcher()
|
|
20
31
|
private val onDragStart by EventDispatcher()
|
|
21
32
|
private val onDrag by EventDispatcher()
|
|
@@ -23,14 +34,45 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
23
34
|
|
|
24
35
|
private var marker: Marker? = null
|
|
25
36
|
private var aMap: AMap? = null
|
|
37
|
+
private var pendingPosition: LatLng? = null
|
|
38
|
+
private var iconWidth: Int = 0 // 用于自定义图标的宽度
|
|
39
|
+
private var iconHeight: Int = 0 // 用于自定义图标的高度
|
|
40
|
+
private var customViewWidth: Int = 0 // 用于自定义视图(children)的宽度
|
|
41
|
+
private var customViewHeight: Int = 0 // 用于自定义视图(children)的高度
|
|
42
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
26
43
|
|
|
27
44
|
/**
|
|
28
45
|
* 设置地图实例
|
|
29
46
|
*/
|
|
30
47
|
@Suppress("unused")
|
|
31
48
|
fun setMap(map: AMap) {
|
|
49
|
+
android.util.Log.d("MarkerView", "🗺️ setMap 被调用,pendingPosition = $pendingPosition, childCount = $childCount")
|
|
32
50
|
aMap = map
|
|
33
51
|
createOrUpdateMarker()
|
|
52
|
+
|
|
53
|
+
// 如果之前已经设置了位置但没有 marker,现在设置位置
|
|
54
|
+
pendingPosition?.let { pos ->
|
|
55
|
+
android.util.Log.d("MarkerView", "✅ 应用待处理的位置: $pos")
|
|
56
|
+
marker?.position = pos
|
|
57
|
+
pendingPosition = null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 如果已经有子视图,触发多次延迟更新确保内容渲染
|
|
61
|
+
if (childCount > 0 && marker != null) {
|
|
62
|
+
android.util.Log.d("MarkerView", "🎨 setMap 后触发延迟更新")
|
|
63
|
+
|
|
64
|
+
// 100ms 后第一次更新
|
|
65
|
+
mainHandler.postDelayed({
|
|
66
|
+
android.util.Log.d("MarkerView", "⏰ setMap 第一次延迟更新(100ms)")
|
|
67
|
+
updateMarkerIcon()
|
|
68
|
+
}, 100)
|
|
69
|
+
|
|
70
|
+
// 300ms 后第二次更新,确保 Text 内容已加载
|
|
71
|
+
mainHandler.postDelayed({
|
|
72
|
+
android.util.Log.d("MarkerView", "⏰ setMap 第二次延迟更新(300ms,确保内容加载)")
|
|
73
|
+
updateMarkerIcon()
|
|
74
|
+
}, 300)
|
|
75
|
+
}
|
|
34
76
|
}
|
|
35
77
|
|
|
36
78
|
/**
|
|
@@ -39,10 +81,25 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
39
81
|
fun setPosition(position: Map<String, Double>) {
|
|
40
82
|
val lat = position["latitude"] ?: return
|
|
41
83
|
val lng = position["longitude"] ?: return
|
|
84
|
+
val latLng = LatLng(lat, lng)
|
|
85
|
+
|
|
86
|
+
android.util.Log.d("MarkerView", "📍 setPosition 被调用: ($lat, $lng), marker = $marker, aMap = $aMap")
|
|
42
87
|
|
|
43
88
|
marker?.let {
|
|
44
|
-
|
|
45
|
-
|
|
89
|
+
android.util.Log.d("MarkerView", "✅ 更新现有 marker 位置")
|
|
90
|
+
it.position = latLng
|
|
91
|
+
pendingPosition = null
|
|
92
|
+
} ?: run {
|
|
93
|
+
android.util.Log.d("MarkerView", "❌ marker 为 null")
|
|
94
|
+
if (aMap != null) {
|
|
95
|
+
android.util.Log.d("MarkerView", "🔧 aMap 存在,创建新 marker")
|
|
96
|
+
createOrUpdateMarker()
|
|
97
|
+
marker?.position = latLng
|
|
98
|
+
} else {
|
|
99
|
+
android.util.Log.d("MarkerView", "⏳ aMap 为 null,保存位置等待 setMap")
|
|
100
|
+
pendingPosition = latLng
|
|
101
|
+
}
|
|
102
|
+
}
|
|
46
103
|
}
|
|
47
104
|
|
|
48
105
|
/**
|
|
@@ -133,15 +190,53 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
133
190
|
marker?.let { it.zIndex = zIndex }
|
|
134
191
|
}
|
|
135
192
|
|
|
193
|
+
/**
|
|
194
|
+
* 设置图标宽度(用于自定义图标 icon 属性)
|
|
195
|
+
*/
|
|
196
|
+
fun setIconWidth(width: Int) {
|
|
197
|
+
iconWidth = width
|
|
198
|
+
android.util.Log.d("MarkerView", "📏 设置 iconWidth: $width")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 设置图标高度(用于自定义图标 icon 属性)
|
|
203
|
+
*/
|
|
204
|
+
fun setIconHeight(height: Int) {
|
|
205
|
+
iconHeight = height
|
|
206
|
+
android.util.Log.d("MarkerView", "📏 设置 iconHeight: $height")
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 设置自定义视图宽度(用于 children 属性)
|
|
211
|
+
*/
|
|
212
|
+
fun setCustomViewWidth(width: Int) {
|
|
213
|
+
customViewWidth = width
|
|
214
|
+
android.util.Log.d("MarkerView", "📏 设置 customViewWidth: $width")
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 设置自定义视图高度(用于 children 属性)
|
|
219
|
+
*/
|
|
220
|
+
fun setCustomViewHeight(height: Int) {
|
|
221
|
+
customViewHeight = height
|
|
222
|
+
android.util.Log.d("MarkerView", "📏 设置 customViewHeight: $height")
|
|
223
|
+
}
|
|
224
|
+
|
|
136
225
|
/**
|
|
137
226
|
* 创建或更新标记
|
|
138
227
|
*/
|
|
139
228
|
private fun createOrUpdateMarker() {
|
|
140
229
|
aMap?.let { map ->
|
|
141
230
|
if (marker == null) {
|
|
231
|
+
android.util.Log.d("MarkerView", "🔧 创建新的 marker")
|
|
142
232
|
val options = MarkerOptions()
|
|
143
233
|
marker = map.addMarker(options)
|
|
144
234
|
|
|
235
|
+
android.util.Log.d("MarkerView", "📌 Marker 已添加到地图,childCount = $childCount")
|
|
236
|
+
|
|
237
|
+
// 不立即更新图标,等待延迟更新(在 addView 和 onLayout 中)
|
|
238
|
+
android.util.Log.d("MarkerView", "⏳ 等待延迟更新图标")
|
|
239
|
+
|
|
145
240
|
// 设置点击监听
|
|
146
241
|
map.setOnMarkerClickListener { clickedMarker ->
|
|
147
242
|
if (clickedMarker == marker) {
|
|
@@ -194,6 +289,225 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
194
289
|
}
|
|
195
290
|
}
|
|
196
291
|
|
|
292
|
+
/**
|
|
293
|
+
* 创建默认 marker 图标 (红色大头针)
|
|
294
|
+
*/
|
|
295
|
+
private fun createDefaultMarkerBitmap(): Bitmap {
|
|
296
|
+
val width = 48
|
|
297
|
+
val height = 72
|
|
298
|
+
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
|
299
|
+
val canvas = Canvas(bitmap)
|
|
300
|
+
|
|
301
|
+
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
302
|
+
paint.color = Color.parseColor("#FF5252")
|
|
303
|
+
paint.style = Paint.Style.FILL
|
|
304
|
+
|
|
305
|
+
// 绘制圆形顶部
|
|
306
|
+
canvas.drawCircle(width / 2f, width / 2f, width / 2f - 2, paint)
|
|
307
|
+
|
|
308
|
+
// 绘制尖端
|
|
309
|
+
val path = Path()
|
|
310
|
+
path.moveTo(width / 2f, height.toFloat())
|
|
311
|
+
path.lineTo(width / 4f, width / 2f + 10f)
|
|
312
|
+
path.lineTo(3 * width / 4f, width / 2f + 10f)
|
|
313
|
+
path.close()
|
|
314
|
+
canvas.drawPath(path, paint)
|
|
315
|
+
|
|
316
|
+
// 绘制白色边框
|
|
317
|
+
paint.color = Color.WHITE
|
|
318
|
+
paint.style = Paint.Style.STROKE
|
|
319
|
+
paint.strokeWidth = 3f
|
|
320
|
+
canvas.drawCircle(width / 2f, width / 2f, width / 2f - 4, paint)
|
|
321
|
+
|
|
322
|
+
return bitmap
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* 将视图转换为 Bitmap
|
|
327
|
+
*/
|
|
328
|
+
private fun createBitmapFromView(): Bitmap? {
|
|
329
|
+
if (childCount == 0) {
|
|
330
|
+
android.util.Log.w("MarkerView", "❌ childCount = 0")
|
|
331
|
+
return null
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return try {
|
|
335
|
+
val childView = getChildAt(0)
|
|
336
|
+
android.util.Log.d("MarkerView", "📦 子视图: $childView")
|
|
337
|
+
|
|
338
|
+
// 获取视图实际测量的尺寸(React Native 已经布局好的)
|
|
339
|
+
val measuredWidth = childView.measuredWidth
|
|
340
|
+
val measuredHeight = childView.measuredHeight
|
|
341
|
+
|
|
342
|
+
android.util.Log.d("MarkerView", "📏 子视图测量尺寸: ${measuredWidth}x${measuredHeight}")
|
|
343
|
+
|
|
344
|
+
// 优先使用已测量的尺寸,其次使用 customViewWidth/customViewHeight(用于 children),最后使用默认值
|
|
345
|
+
// 注意:iconWidth/iconHeight 是用于自定义图标的,不用于 children
|
|
346
|
+
val finalWidth = if (measuredWidth > 0) measuredWidth else (if (customViewWidth > 0) customViewWidth else 240)
|
|
347
|
+
val finalHeight = if (measuredHeight > 0) measuredHeight else (if (customViewHeight > 0) customViewHeight else 80)
|
|
348
|
+
|
|
349
|
+
android.util.Log.d("MarkerView", "📏 最终使用尺寸: ${finalWidth}x${finalHeight} (customViewWidth=$customViewWidth, customViewHeight=$customViewHeight)")
|
|
350
|
+
|
|
351
|
+
// 打印视图层次结构以调试
|
|
352
|
+
if (childView is android.view.ViewGroup) {
|
|
353
|
+
android.util.Log.d("MarkerView", "📦 子视图有 ${childView.childCount} 个子视图:")
|
|
354
|
+
for (i in 0 until childView.childCount) {
|
|
355
|
+
val child = childView.getChildAt(i)
|
|
356
|
+
android.util.Log.d("MarkerView", " └─ 子视图[$i]: ${child.javaClass.simpleName}, 可见性: ${child.visibility}")
|
|
357
|
+
if (child is android.widget.TextView) {
|
|
358
|
+
android.util.Log.d("MarkerView", " 文字: '${child.text}', 颜色: ${Integer.toHexString(child.currentTextColor)}, 大小: ${child.textSize}")
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (finalWidth <= 0 || finalHeight <= 0) {
|
|
364
|
+
android.util.Log.w("MarkerView", "❌ 最终尺寸无效: ${finalWidth}x${finalHeight}")
|
|
365
|
+
return null
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 如果需要重新测量(尺寸改变了)
|
|
369
|
+
if (measuredWidth != finalWidth || measuredHeight != finalHeight) {
|
|
370
|
+
childView.measure(
|
|
371
|
+
MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
|
|
372
|
+
MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY)
|
|
373
|
+
)
|
|
374
|
+
childView.layout(0, 0, finalWidth, finalHeight)
|
|
375
|
+
android.util.Log.d("MarkerView", "✅ 子视图已重新测量和布局")
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// 创建 Bitmap
|
|
379
|
+
val bitmap = Bitmap.createBitmap(finalWidth, finalHeight, Bitmap.Config.ARGB_8888)
|
|
380
|
+
val canvas = Canvas(bitmap)
|
|
381
|
+
|
|
382
|
+
// 设置背景为透明
|
|
383
|
+
canvas.drawColor(android.graphics.Color.TRANSPARENT)
|
|
384
|
+
|
|
385
|
+
// 绘制视图及其所有子视图
|
|
386
|
+
childView.draw(canvas)
|
|
387
|
+
android.util.Log.d("MarkerView", "🎨 Bitmap 已绘制,尺寸: ${bitmap.width}x${bitmap.height}")
|
|
388
|
+
|
|
389
|
+
bitmap
|
|
390
|
+
} catch (e: Exception) {
|
|
391
|
+
android.util.Log.e("MarkerView", "❌ 创建 Bitmap 失败", e)
|
|
392
|
+
e.printStackTrace()
|
|
393
|
+
null
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* 创建组合 Bitmap:默认 marker + 自定义内容
|
|
399
|
+
*/
|
|
400
|
+
private fun createCombinedBitmap(): Bitmap? {
|
|
401
|
+
android.util.Log.d("MarkerView", "🖼️ createCombinedBitmap 开始")
|
|
402
|
+
val customBitmap = createBitmapFromView()
|
|
403
|
+
if (customBitmap == null) {
|
|
404
|
+
android.util.Log.w("MarkerView", "❌ 自定义 Bitmap 为 null")
|
|
405
|
+
return null
|
|
406
|
+
}
|
|
407
|
+
android.util.Log.d("MarkerView", "✅ 自定义 Bitmap: ${customBitmap.width}x${customBitmap.height}")
|
|
408
|
+
|
|
409
|
+
val markerBitmap = createDefaultMarkerBitmap()
|
|
410
|
+
android.util.Log.d("MarkerView", "✅ 默认 Marker Bitmap: ${markerBitmap.width}x${markerBitmap.height}")
|
|
411
|
+
|
|
412
|
+
// 计算总尺寸:marker 在下,自定义内容在上
|
|
413
|
+
val totalWidth = maxOf(markerBitmap.width, customBitmap.width)
|
|
414
|
+
val totalHeight = markerBitmap.height + customBitmap.height + 10 // 10px 间距
|
|
415
|
+
|
|
416
|
+
android.util.Log.d("MarkerView", "📐 组合尺寸: ${totalWidth}x${totalHeight}")
|
|
417
|
+
|
|
418
|
+
val combinedBitmap = Bitmap.createBitmap(totalWidth, totalHeight, Bitmap.Config.ARGB_8888)
|
|
419
|
+
val canvas = Canvas(combinedBitmap)
|
|
420
|
+
|
|
421
|
+
// 绘制自定义内容在上方
|
|
422
|
+
val customX = (totalWidth - customBitmap.width) / 2f
|
|
423
|
+
canvas.drawBitmap(customBitmap, customX, 0f, null)
|
|
424
|
+
android.util.Log.d("MarkerView", "🎨 已绘制自定义内容在 ($customX, 0)")
|
|
425
|
+
|
|
426
|
+
// 绘制 marker 在下方
|
|
427
|
+
val markerX = (totalWidth - markerBitmap.width) / 2f
|
|
428
|
+
val markerY = customBitmap.height + 10f
|
|
429
|
+
canvas.drawBitmap(markerBitmap, markerX, markerY, null)
|
|
430
|
+
android.util.Log.d("MarkerView", "📍 已绘制 marker 在 ($markerX, $markerY)")
|
|
431
|
+
|
|
432
|
+
return combinedBitmap
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* 更新 marker 图标
|
|
437
|
+
*/
|
|
438
|
+
private fun updateMarkerIcon() {
|
|
439
|
+
android.util.Log.d("MarkerView", "🔄 updateMarkerIcon 被调用,childCount = $childCount")
|
|
440
|
+
|
|
441
|
+
if (childCount > 0) {
|
|
442
|
+
android.util.Log.d("MarkerView", "🎨 开始创建自定义 Bitmap(仅自定义内容)")
|
|
443
|
+
val customBitmap = createBitmapFromView()
|
|
444
|
+
customBitmap?.let {
|
|
445
|
+
android.util.Log.d("MarkerView", "✅ 自定义 Bitmap 创建成功,尺寸: ${it.width}x${it.height}")
|
|
446
|
+
|
|
447
|
+
marker?.setIcon(BitmapDescriptorFactory.fromBitmap(it))
|
|
448
|
+
|
|
449
|
+
// 设置 anchor 为底部中心,让自定义内容底部对齐地图坐标点
|
|
450
|
+
val anchorX = 0.5f // 水平居中
|
|
451
|
+
val anchorY = 1.0f // 垂直底部
|
|
452
|
+
android.util.Log.d("MarkerView", "🎯 设置 marker anchor: ($anchorX, $anchorY)")
|
|
453
|
+
marker?.setAnchor(anchorX, anchorY)
|
|
454
|
+
|
|
455
|
+
android.util.Log.d("MarkerView", "🎯 图标已设置到 marker")
|
|
456
|
+
} ?: run {
|
|
457
|
+
android.util.Log.w("MarkerView", "❌ 自定义 Bitmap 创建失败")
|
|
458
|
+
marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
android.util.Log.d("MarkerView", "📍 没有子视图,使用默认图标")
|
|
462
|
+
marker?.setIcon(BitmapDescriptorFactory.defaultMarker())
|
|
463
|
+
marker?.setAnchor(0.5f, 1.0f) // 默认 anchor
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
override fun addView(child: View?, index: Int, params: android.view.ViewGroup.LayoutParams?) {
|
|
469
|
+
android.util.Log.d("MarkerView", "➕ addView 被调用,child = $child")
|
|
470
|
+
super.addView(child, index, params)
|
|
471
|
+
|
|
472
|
+
// 延迟更新图标,等待 React Native 样式和内容渲染
|
|
473
|
+
android.util.Log.d("MarkerView", "✅ 子视图已添加,准备延迟更新,marker=${marker}")
|
|
474
|
+
mainHandler.postDelayed({
|
|
475
|
+
android.util.Log.d("MarkerView", "⏰ 第一次延迟更新图标,marker=${marker}")
|
|
476
|
+
if (marker != null) {
|
|
477
|
+
updateMarkerIcon()
|
|
478
|
+
} else {
|
|
479
|
+
android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过第一次更新")
|
|
480
|
+
}
|
|
481
|
+
}, 50)
|
|
482
|
+
|
|
483
|
+
mainHandler.postDelayed({
|
|
484
|
+
android.util.Log.d("MarkerView", "⏰ 第二次延迟更新图标(确保内容加载),marker=${marker}")
|
|
485
|
+
if (marker != null) {
|
|
486
|
+
updateMarkerIcon()
|
|
487
|
+
} else {
|
|
488
|
+
android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过第二次更新")
|
|
489
|
+
}
|
|
490
|
+
}, 150)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
494
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
495
|
+
android.util.Log.d("MarkerView", "📐 onLayout: changed=$changed, bounds=(${left},${top},${right},${bottom}), marker=${marker}")
|
|
496
|
+
|
|
497
|
+
// 布局完成后再次尝试更新图标(确保样式已应用)
|
|
498
|
+
if (changed && childCount > 0) {
|
|
499
|
+
android.util.Log.d("MarkerView", "🔄 布局改变,延迟更新图标,marker=${marker}")
|
|
500
|
+
mainHandler.postDelayed({
|
|
501
|
+
android.util.Log.d("MarkerView", "⏰ onLayout 延迟更新执行,marker=${marker}")
|
|
502
|
+
if (marker != null) {
|
|
503
|
+
updateMarkerIcon()
|
|
504
|
+
} else {
|
|
505
|
+
android.util.Log.w("MarkerView", "⚠️ marker 为 null,跳过 onLayout 更新")
|
|
506
|
+
}
|
|
507
|
+
}, 200)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
197
511
|
/**
|
|
198
512
|
* 移除标记
|
|
199
513
|
*/
|
|
@@ -207,3 +521,4 @@ class MarkerView(context: Context, appContext: AppContext) : ExpoView(context, a
|
|
|
207
521
|
removeMarker()
|
|
208
522
|
}
|
|
209
523
|
}
|
|
524
|
+
|
|
@@ -44,6 +44,22 @@ class MarkerViewModule : Module() {
|
|
|
44
44
|
Prop<Map<String, Float>>("anchor") { view: MarkerView, anchor ->
|
|
45
45
|
view.setAnchor(anchor)
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
Prop<Int>("iconWidth") { view: MarkerView, width ->
|
|
49
|
+
view.setIconWidth(width)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Prop<Int>("iconHeight") { view: MarkerView, height ->
|
|
53
|
+
view.setIconHeight(height)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Prop<Int>("customViewWidth") { view: MarkerView, width ->
|
|
57
|
+
view.setCustomViewWidth(width)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Prop<Int>("customViewHeight") { view: MarkerView, height ->
|
|
61
|
+
view.setCustomViewHeight(height)
|
|
62
|
+
}
|
|
47
63
|
}
|
|
48
64
|
}
|
|
49
65
|
}
|
|
@@ -23,6 +23,8 @@ object ColorParser {
|
|
|
23
23
|
return try {
|
|
24
24
|
when {
|
|
25
25
|
color.startsWith("#") -> Color.parseColor(color)
|
|
26
|
+
color.startsWith("rgba(") -> parseRgbaColor(color)
|
|
27
|
+
color.startsWith("rgb(") -> parseRgbColor(color)
|
|
26
28
|
else -> getNamedColor(color)
|
|
27
29
|
}
|
|
28
30
|
} catch (e: Exception) {
|
|
@@ -30,6 +32,29 @@ object ColorParser {
|
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
private fun parseRgbaColor(color: String): Int {
|
|
36
|
+
val values = color.substringAfter("rgba(").substringBefore(")").split(",").map { it.trim() }
|
|
37
|
+
if (values.size != 4) return Color.BLACK
|
|
38
|
+
|
|
39
|
+
val r = values[0].toIntOrNull() ?: return Color.BLACK
|
|
40
|
+
val g = values[1].toIntOrNull() ?: return Color.BLACK
|
|
41
|
+
val b = values[2].toIntOrNull() ?: return Color.BLACK
|
|
42
|
+
val a = (values[3].toFloatOrNull()?.times(255))?.toInt() ?: return Color.BLACK
|
|
43
|
+
|
|
44
|
+
return Color.argb(a, r, g, b)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun parseRgbColor(color: String): Int {
|
|
48
|
+
val values = color.substringAfter("rgb(").substringBefore(")").split(",").map { it.trim() }
|
|
49
|
+
if (values.size != 3) return Color.BLACK
|
|
50
|
+
|
|
51
|
+
val r = values[0].toIntOrNull() ?: return Color.BLACK
|
|
52
|
+
val g = values[1].toIntOrNull() ?: return Color.BLACK
|
|
53
|
+
val b = values[2].toIntOrNull() ?: return Color.BLACK
|
|
54
|
+
|
|
55
|
+
return Color.rgb(r, g, b)
|
|
56
|
+
}
|
|
57
|
+
|
|
33
58
|
private fun getNamedColor(name: String): Int {
|
|
34
59
|
return when (name.lowercase()) {
|
|
35
60
|
"red" -> Color.RED
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Circle.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/Circle.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Circle.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/Circle.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,WAAW,qBAOhD"}
|