expo-gaode-map 1.0.2 → 1.0.3

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 (49) hide show
  1. package/README.md +1 -0
  2. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +17 -1
  3. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +52 -5
  4. package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +184 -6
  5. package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +24 -51
  6. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +3 -0
  7. package/build/ExpoGaodeMapView.d.ts +26 -1
  8. package/build/ExpoGaodeMapView.d.ts.map +1 -1
  9. package/build/ExpoGaodeMapView.js +82 -1
  10. package/build/ExpoGaodeMapView.js.map +1 -1
  11. package/build/components/overlays/Circle.d.ts +0 -20
  12. package/build/components/overlays/Circle.d.ts.map +1 -1
  13. package/build/components/overlays/Circle.js +28 -45
  14. package/build/components/overlays/Circle.js.map +1 -1
  15. package/build/components/overlays/Marker.d.ts +2 -16
  16. package/build/components/overlays/Marker.d.ts.map +1 -1
  17. package/build/components/overlays/Marker.js +60 -37
  18. package/build/components/overlays/Marker.js.map +1 -1
  19. package/build/components/overlays/Polygon.d.ts.map +1 -1
  20. package/build/components/overlays/Polygon.js +28 -49
  21. package/build/components/overlays/Polygon.js.map +1 -1
  22. package/build/components/overlays/Polyline.d.ts.map +1 -1
  23. package/build/components/overlays/Polyline.js +22 -11
  24. package/build/components/overlays/Polyline.js.map +1 -1
  25. package/build/types/map-view.types.d.ts +30 -0
  26. package/build/types/map-view.types.d.ts.map +1 -1
  27. package/build/types/map-view.types.js.map +1 -1
  28. package/build/types/overlays.types.d.ts +25 -1
  29. package/build/types/overlays.types.d.ts.map +1 -1
  30. package/build/types/overlays.types.js.map +1 -1
  31. package/docs/API.md +40 -0
  32. package/docs/EXAMPLES.md +86 -2
  33. package/expo-module.config.json +1 -1
  34. package/ios/ExpoGaodeMapModule.swift +42 -14
  35. package/ios/ExpoGaodeMapView.swift +210 -7
  36. package/ios/managers/OverlayManager.swift +78 -10
  37. package/ios/overlays/CircleView.swift +41 -12
  38. package/ios/overlays/MarkerView.swift +55 -3
  39. package/ios/overlays/PolygonView.swift +25 -5
  40. package/ios/overlays/PolylineView.swift +23 -4
  41. package/ios/utils/ColorParser.swift +0 -5
  42. package/package.json +1 -1
  43. package/src/ExpoGaodeMapView.tsx +118 -1
  44. package/src/components/overlays/Circle.tsx +31 -48
  45. package/src/components/overlays/Marker.tsx +69 -42
  46. package/src/components/overlays/Polygon.tsx +34 -50
  47. package/src/components/overlays/Polyline.tsx +29 -14
  48. package/src/types/map-view.types.ts +25 -0
  49. package/src/types/overlays.types.ts +30 -1
@@ -3,13 +3,20 @@ import MAMapKit
3
3
 
4
4
  /**
5
5
  * 标记点视图
6
- *
6
+ *
7
7
  * 负责:
8
8
  * - 在地图上显示标记点
9
9
  * - 管理标记点属性(位置、标题、描述)
10
10
  * - 支持拖拽功能
11
+ * - 支持自定义 children 视图
11
12
  */
12
13
  class MarkerView: ExpoView {
14
+ // MARK: - 事件派发器
15
+ let onPress = EventDispatcher()
16
+ let onDragStart = EventDispatcher()
17
+ let onDrag = EventDispatcher()
18
+ let onDragEnd = EventDispatcher()
19
+
13
20
  /// 标记点位置
14
21
  var position: [String: Double] = [:]
15
22
  /// 标题
@@ -18,11 +25,27 @@ class MarkerView: ExpoView {
18
25
  var markerDescription: String = ""
19
26
  /// 是否可拖拽
20
27
  var draggable: Bool = false
28
+ /// 图标 URI
29
+ var iconUri: String?
30
+ /// 图标宽度
31
+ var iconWidth: Double = 40
32
+ /// 图标高度
33
+ var iconHeight: Double = 40
34
+ /// 中心偏移
35
+ var centerOffset: [String: Double]?
36
+ /// 是否显示动画
37
+ var animatesDrop: Bool = false
38
+ /// 大头针颜色
39
+ var pinColor: String = "red"
40
+ /// 是否显示气泡
41
+ var canShowCallout: Bool = true
21
42
 
22
43
  /// 地图视图弱引用
23
44
  private var mapView: MAMapView?
24
45
  /// 标记点对象
25
- private var annotation: MAPointAnnotation?
46
+ var annotation: MAPointAnnotation?
47
+ /// 标记点视图
48
+ private var annotationView: MAAnnotationView?
26
49
 
27
50
  required init(appContext: AppContext? = nil) {
28
51
  super.init(appContext: appContext)
@@ -60,6 +83,9 @@ class MarkerView: ExpoView {
60
83
 
61
84
  mapView.addAnnotation(annotation)
62
85
  self.annotation = annotation
86
+
87
+ // 获取 annotationView
88
+ annotationView = mapView.view(for: annotation)
63
89
  }
64
90
 
65
91
  /**
@@ -95,7 +121,33 @@ class MarkerView: ExpoView {
95
121
  */
96
122
  func setDraggable(_ draggable: Bool) {
97
123
  self.draggable = draggable
98
- // iOS 高德地图标记默认不可拖拽,需要自定义实现
124
+ updateAnnotation()
125
+ }
126
+
127
+ func setIcon(_ source: [String: Any]?) {
128
+ if let dict = source {
129
+ // 处理 require() 返回的对象
130
+ if let uri = dict["uri"] as? String {
131
+ self.iconUri = uri
132
+ }
133
+ }
134
+ updateAnnotation()
135
+ }
136
+
137
+ func setCenterOffset(_ offset: [String: Double]) {
138
+ self.centerOffset = offset
139
+ }
140
+
141
+ func setAnimatesDrop(_ animate: Bool) {
142
+ self.animatesDrop = animate
143
+ }
144
+
145
+ func setPinColor(_ color: String) {
146
+ self.pinColor = color
147
+ }
148
+
149
+ func setCanShowCallout(_ show: Bool) {
150
+ self.canShowCallout = show
99
151
  }
100
152
 
101
153
  /**
@@ -43,17 +43,29 @@ class PolygonView: ExpoView {
43
43
  * 更新多边形覆盖物
44
44
  */
45
45
  private func updatePolygon() {
46
- guard let mapView = mapView else { return }
46
+ guard let mapView = mapView else {
47
+ print("❌ PolygonView.updatePolygon: mapView 为空")
48
+ return
49
+ }
47
50
  if let old = polygon { mapView.remove(old) }
48
51
 
49
52
  var coords = points.compactMap { point -> CLLocationCoordinate2D? in
50
53
  guard let lat = point["latitude"], let lng = point["longitude"] else { return nil }
51
54
  return CLLocationCoordinate2D(latitude: lat, longitude: lng)
52
55
  }
53
- guard !coords.isEmpty else { return }
56
+ guard !coords.isEmpty else {
57
+ print("❌ PolygonView.updatePolygon: 点数组为空")
58
+ return
59
+ }
60
+
61
+ print("🔶 PolygonView.updatePolygon: points=\(coords.count)个点")
62
+ print("🔶 PolygonView.updatePolygon: fillColor=\(String(describing: fillColor)), strokeColor=\(String(describing: strokeColor)), strokeWidth=\(strokeWidth)")
54
63
 
55
64
  polygon = MAPolygon(coordinates: &coords, count: UInt(coords.count))
56
65
  mapView.add(polygon!)
66
+
67
+ renderer = nil
68
+ print("🔶 PolygonView.updatePolygon: renderer 已清空")
57
69
  }
58
70
 
59
71
  /**
@@ -63,9 +75,15 @@ class PolygonView: ExpoView {
63
75
  func getRenderer() -> MAOverlayRenderer {
64
76
  if renderer == nil, let polygon = polygon {
65
77
  renderer = MAPolygonRenderer(polygon: polygon)
66
- renderer?.fillColor = ColorParser.parseColor(fillColor) ?? UIColor.clear
67
- renderer?.strokeColor = ColorParser.parseColor(strokeColor) ?? UIColor.clear
78
+ let parsedFillColor = ColorParser.parseColor(fillColor)
79
+ let parsedStrokeColor = ColorParser.parseColor(strokeColor)
80
+ renderer?.fillColor = parsedFillColor ?? UIColor.clear
81
+ renderer?.strokeColor = parsedStrokeColor ?? UIColor.clear
68
82
  renderer?.lineWidth = CGFloat(strokeWidth)
83
+ print("🔶 PolygonView.getRenderer: 创建新 renderer")
84
+ print("🔶 PolygonView.getRenderer: fillColor=\(String(describing: parsedFillColor)), strokeColor=\(String(describing: parsedStrokeColor)), lineWidth=\(strokeWidth)")
85
+ } else {
86
+ print("🔶 PolygonView.getRenderer: 使用缓存的 renderer")
69
87
  }
70
88
  return renderer!
71
89
  }
@@ -76,7 +94,6 @@ class PolygonView: ExpoView {
76
94
  */
77
95
  func setPoints(_ points: [[String: Double]]) {
78
96
  self.points = points
79
- renderer = nil
80
97
  updatePolygon()
81
98
  }
82
99
 
@@ -85,6 +102,7 @@ class PolygonView: ExpoView {
85
102
  * @param color 颜色值
86
103
  */
87
104
  func setFillColor(_ color: Any?) {
105
+ print("🔶 PolygonView.setFillColor: \(String(describing: color))")
88
106
  fillColor = color
89
107
  renderer = nil
90
108
  updatePolygon()
@@ -95,6 +113,7 @@ class PolygonView: ExpoView {
95
113
  * @param color 颜色值
96
114
  */
97
115
  func setStrokeColor(_ color: Any?) {
116
+ print("🔶 PolygonView.setStrokeColor: \(String(describing: color))")
98
117
  strokeColor = color
99
118
  renderer = nil
100
119
  updatePolygon()
@@ -105,6 +124,7 @@ class PolygonView: ExpoView {
105
124
  * @param width 宽度值
106
125
  */
107
126
  func setStrokeWidth(_ width: Float) {
127
+ print("🔶 PolygonView.setStrokeWidth: \(width)")
108
128
  strokeWidth = width
109
129
  renderer = nil
110
130
  updatePolygon()
@@ -43,17 +43,29 @@ class PolylineView: ExpoView {
43
43
  * 更新折线覆盖物
44
44
  */
45
45
  private func updatePolyline() {
46
- guard let mapView = mapView else { return }
46
+ guard let mapView = mapView else {
47
+ print("❌ PolylineView.updatePolyline: mapView 为空")
48
+ return
49
+ }
47
50
  if let old = polyline { mapView.remove(old) }
48
51
 
49
52
  var coords = points.compactMap { point -> CLLocationCoordinate2D? in
50
53
  guard let lat = point["latitude"], let lng = point["longitude"] else { return nil }
51
54
  return CLLocationCoordinate2D(latitude: lat, longitude: lng)
52
55
  }
53
- guard !coords.isEmpty else { return }
56
+ guard !coords.isEmpty else {
57
+ print("❌ PolylineView.updatePolyline: 点数组为空")
58
+ return
59
+ }
60
+
61
+ print("🔷 PolylineView.updatePolyline: points=\(coords.count)个点")
62
+ print("🔷 PolylineView.updatePolyline: strokeColor=\(String(describing: strokeColor)), strokeWidth=\(strokeWidth), texture=\(String(describing: textureUrl))")
54
63
 
55
64
  polyline = MAPolyline(coordinates: &coords, count: UInt(coords.count))
56
65
  mapView.add(polyline!)
66
+
67
+ renderer = nil
68
+ print("🔷 PolylineView.updatePolyline: renderer 已清空")
57
69
  }
58
70
 
59
71
  /**
@@ -66,10 +78,15 @@ class PolylineView: ExpoView {
66
78
  renderer?.lineWidth = CGFloat(strokeWidth)
67
79
 
68
80
  if let url = textureUrl {
81
+ print("🔷 PolylineView.getRenderer: 加载纹理 \(url)")
69
82
  loadTexture(url: url, renderer: renderer!)
70
83
  } else {
71
- renderer?.strokeColor = ColorParser.parseColor(strokeColor) ?? UIColor.clear
84
+ let parsedColor = ColorParser.parseColor(strokeColor)
85
+ renderer?.strokeColor = parsedColor ?? UIColor.clear
86
+ print("🔷 PolylineView.getRenderer: 创建新 renderer, strokeColor=\(String(describing: parsedColor)), lineWidth=\(strokeWidth)")
72
87
  }
88
+ } else {
89
+ print("🔷 PolylineView.getRenderer: 使用缓存的 renderer")
73
90
  }
74
91
  return renderer!
75
92
  }
@@ -126,7 +143,6 @@ class PolylineView: ExpoView {
126
143
  */
127
144
  func setPoints(_ points: [[String: Double]]) {
128
145
  self.points = points
129
- renderer = nil
130
146
  updatePolyline()
131
147
  }
132
148
 
@@ -135,6 +151,7 @@ class PolylineView: ExpoView {
135
151
  * @param width 线宽值
136
152
  */
137
153
  func setStrokeWidth(_ width: Float) {
154
+ print("🔷 PolylineView.setStrokeWidth: \(width)")
138
155
  strokeWidth = width
139
156
  renderer = nil
140
157
  updatePolyline()
@@ -145,6 +162,7 @@ class PolylineView: ExpoView {
145
162
  * @param color 颜色值
146
163
  */
147
164
  func setStrokeColor(_ color: Any?) {
165
+ print("🔷 PolylineView.setStrokeColor: \(String(describing: color))")
148
166
  strokeColor = color
149
167
  renderer = nil
150
168
  updatePolyline()
@@ -155,6 +173,7 @@ class PolylineView: ExpoView {
155
173
  * @param url 图片 URL
156
174
  */
157
175
  func setTexture(_ url: String?) {
176
+ print("🔷 PolylineView.setTexture: \(String(describing: url))")
158
177
  textureUrl = url
159
178
  renderer = nil
160
179
  updatePolyline()
@@ -12,12 +12,10 @@ class ColorParser {
12
12
  static func parseColor(_ colorValue: Any?) -> UIColor? {
13
13
  guard let colorValue = colorValue else { return nil }
14
14
 
15
- // 如果是数字类型
16
15
  if let number = colorValue as? Int {
17
16
  return UIColor(hex: number)
18
17
  }
19
18
 
20
- // 如果是字符串类型
21
19
  if let string = colorValue as? String {
22
20
  return parseColorString(string)
23
21
  }
@@ -79,12 +77,10 @@ class ColorParser {
79
77
  var hexNumber: UInt64 = 0
80
78
 
81
79
  if scanner.scanHexInt64(&hexNumber) {
82
- // 尝试 ARGB 格式(Android 风格)
83
80
  let alphaARGB = CGFloat((hexNumber & 0xff000000) >> 24) / 255
84
81
  let redARGB = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
85
82
  let greenARGB = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
86
83
  let blueARGB = CGFloat(hexNumber & 0x000000ff) / 255
87
-
88
84
  return UIColor(red: redARGB, green: greenARGB, blue: blueARGB, alpha: alphaARGB)
89
85
  }
90
86
  }
@@ -98,7 +94,6 @@ class ColorParser {
98
94
  let red = CGFloat((hexNumber & 0xff0000) >> 16) / 255
99
95
  let green = CGFloat((hexNumber & 0x00ff00) >> 8) / 255
100
96
  let blue = CGFloat(hexNumber & 0x0000ff) / 255
101
-
102
97
  return UIColor(red: red, green: green, blue: blue, alpha: alpha)
103
98
  }
104
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "一个功能完整的高德地图 React Native 组件库,基于 Expo Modules 开发,提供地图显示、定位、覆盖物等功能。",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -22,6 +22,61 @@ const NativeView: React.ComponentType<MapViewProps & { ref?: React.Ref<NativeMap
22
22
  // 创建 Context 用于子组件访问 MapRef
23
23
  export const MapContext = React.createContext<React.RefObject<MapViewRef | null> | null>(null);
24
24
 
25
+ // Marker 事件管理器
26
+ type MarkerEventCallbacks = {
27
+ onPress?: () => void;
28
+ onDragStart?: () => void;
29
+ onDrag?: () => void;
30
+ onDragEnd?: (event: { nativeEvent: LatLng }) => void;
31
+ };
32
+
33
+ class MarkerEventManager {
34
+ private callbacks = new Map<string, MarkerEventCallbacks>();
35
+
36
+ register(markerId: string, callbacks: MarkerEventCallbacks) {
37
+ this.callbacks.set(markerId, callbacks);
38
+ }
39
+
40
+ unregister(markerId: string) {
41
+ this.callbacks.delete(markerId);
42
+ }
43
+
44
+ trigger(markerId: string, eventType: keyof MarkerEventCallbacks, data?: any) {
45
+ const callbacks = this.callbacks.get(markerId);
46
+ if (callbacks && callbacks[eventType]) {
47
+ callbacks[eventType]!(data);
48
+ }
49
+ }
50
+ }
51
+
52
+ export const MarkerEventContext = React.createContext<MarkerEventManager | null>(null);
53
+
54
+ // Circle 事件管理器
55
+ type CircleEventCallbacks = {
56
+ onPress?: () => void;
57
+ };
58
+
59
+ class CircleEventManager {
60
+ private callbacks = new Map<string, CircleEventCallbacks>();
61
+
62
+ register(circleId: string, callbacks: CircleEventCallbacks) {
63
+ this.callbacks.set(circleId, callbacks);
64
+ }
65
+
66
+ unregister(circleId: string) {
67
+ this.callbacks.delete(circleId);
68
+ }
69
+
70
+ trigger(circleId: string, eventType: keyof CircleEventCallbacks) {
71
+ const callbacks = this.callbacks.get(circleId);
72
+ if (callbacks && callbacks[eventType]) {
73
+ callbacks[eventType]!();
74
+ }
75
+ }
76
+ }
77
+
78
+ export const CircleEventContext = React.createContext<CircleEventManager | null>(null);
79
+
25
80
  /**
26
81
  * 高德地图视图组件,提供地图操作API和覆盖物管理功能
27
82
  *
@@ -43,6 +98,54 @@ export const MapContext = React.createContext<React.RefObject<MapViewRef | null>
43
98
  const ExpoGaodeMapView = React.forwardRef<MapViewRef, MapViewProps>((props, ref) => {
44
99
  const nativeRef = React.useRef<NativeMapViewRef>(null);
45
100
  const internalRef = React.useRef<MapViewRef | null>(null);
101
+ const markerEventManager = React.useRef(new MarkerEventManager()).current;
102
+ const circleEventManager = React.useRef(new CircleEventManager()).current;
103
+
104
+ // 处理 Marker 事件
105
+ const handleMarkerPress = React.useCallback((event: any) => {
106
+ const markerId = event.nativeEvent?.markerId;
107
+ if (markerId) {
108
+ markerEventManager.trigger(markerId, 'onPress');
109
+ }
110
+ props.onMarkerPress?.(event);
111
+ }, [props.onMarkerPress]);
112
+
113
+ const handleMarkerDragStart = React.useCallback((event: any) => {
114
+ const markerId = event.nativeEvent?.markerId;
115
+ if (markerId) {
116
+ markerEventManager.trigger(markerId, 'onDragStart');
117
+ }
118
+ props.onMarkerDragStart?.(event);
119
+ }, [props.onMarkerDragStart]);
120
+
121
+ const handleMarkerDrag = React.useCallback((event: any) => {
122
+ const markerId = event.nativeEvent?.markerId;
123
+ if (markerId) {
124
+ markerEventManager.trigger(markerId, 'onDrag');
125
+ }
126
+ props.onMarkerDrag?.(event);
127
+ }, [props.onMarkerDrag]);
128
+
129
+ const handleMarkerDragEnd = React.useCallback((event: any) => {
130
+ const markerId = event.nativeEvent?.markerId;
131
+ if (markerId) {
132
+ markerEventManager.trigger(markerId, 'onDragEnd', {
133
+ nativeEvent: {
134
+ latitude: event.nativeEvent.latitude,
135
+ longitude: event.nativeEvent.longitude
136
+ }
137
+ });
138
+ }
139
+ props.onMarkerDragEnd?.(event);
140
+ }, [props.onMarkerDragEnd]);
141
+
142
+ const handleCirclePress = React.useCallback((event: any) => {
143
+ const circleId = event.nativeEvent?.circleId;
144
+ if (circleId) {
145
+ circleEventManager.trigger(circleId, 'onPress');
146
+ }
147
+ props.onCirclePress?.(event);
148
+ }, [props.onCirclePress]);
46
149
 
47
150
  const apiRef: MapViewRef = React.useMemo(() => ({
48
151
  /**
@@ -243,7 +346,21 @@ const ExpoGaodeMapView = React.forwardRef<MapViewRef, MapViewProps>((props, ref)
243
346
 
244
347
  return (
245
348
  <MapContext.Provider value={internalRef}>
246
- <NativeView ref={nativeRef} {...props} />
349
+ <MarkerEventContext.Provider value={markerEventManager}>
350
+ <CircleEventContext.Provider value={circleEventManager}>
351
+ <NativeView
352
+ ref={nativeRef}
353
+ {...props}
354
+ onMarkerPress={handleMarkerPress}
355
+ onMarkerDragStart={handleMarkerDragStart}
356
+ onMarkerDrag={handleMarkerDrag}
357
+ onMarkerDragEnd={handleMarkerDragEnd}
358
+ onCirclePress={handleCirclePress}
359
+ >
360
+ {props.children}
361
+ </NativeView>
362
+ </CircleEventContext.Provider>
363
+ </MarkerEventContext.Provider>
247
364
  </MapContext.Provider>
248
365
  );
249
366
  });
@@ -1,72 +1,55 @@
1
1
  import * as React from 'react';
2
2
  import type { CircleProps } from '../../types';
3
- import { MapContext } from '../../ExpoGaodeMapView';
3
+ import { MapContext, CircleEventContext } from '../../ExpoGaodeMapView';
4
4
 
5
- /**
6
- * Circle 组件 - 高德地图圆形覆盖物
7
- *
8
- * 该组件用于在高德地图上绘制圆形覆盖物,支持动态更新圆形属性。
9
- *
10
- * @param {CircleProps} props - 圆形属性配置
11
- * @param {LatLng} props.center - 圆形中心点坐标
12
- * @param {number} props.radius - 圆形半径(米)
13
- * @param {string} props.fillColor - 填充颜色(十六进制或RGBA)
14
- * @param {string} props.strokeColor - 边框颜色(十六进制或RGBA)
15
- * @param {number} props.strokeWidth - 边框宽度(像素)
16
- *
17
- * @returns {null} 该组件不渲染任何UI元素
18
- *
19
- * @remarks
20
- * 1. 组件挂载时自动添加圆形到地图
21
- * 2. 组件卸载时自动移除圆形
22
- * 3. 当中心点、半径、颜色等属性变化时自动更新圆形
23
- * 4. 使用 React Context 获取地图实例引用
24
- */
25
5
  export default function Circle(props: CircleProps) {
26
6
  const mapRef = React.useContext(MapContext);
7
+ const eventManager = React.useContext(CircleEventContext);
27
8
  const circleIdRef = React.useRef<string | null>(null);
9
+ const propsRef = React.useRef(props);
28
10
 
29
- console.log('Circle 组件渲染,props:', JSON.stringify(props));
11
+ React.useEffect(() => {
12
+ propsRef.current = props;
13
+ }, [props]);
30
14
 
31
15
  React.useEffect(() => {
32
- console.log('Circle useEffect - 添加圆形到地图');
33
-
34
- if (!mapRef?.current) {
35
- console.warn('MapRef 不可用');
36
- return;
37
- }
38
-
39
- // 添加圆形
40
- const circleId = `circle_${Date.now()}_${Math.random()}`;
41
- circleIdRef.current = circleId;
16
+ const checkAndAdd = () => {
17
+ if (!mapRef?.current) {
18
+ setTimeout(checkAndAdd, 50);
19
+ return;
20
+ }
21
+
22
+ const circleId = `circle_${Date.now()}_${Math.random()}`;
23
+ circleIdRef.current = circleId;
24
+
25
+ if (eventManager && props.onPress) {
26
+ eventManager.register(circleId, {
27
+ onPress: props.onPress,
28
+ });
29
+ }
30
+
31
+ mapRef.current.addCircle(circleId, propsRef.current);
32
+ };
42
33
 
43
- mapRef.current.addCircle(circleId, props);
44
- console.log('✅ 圆形已添加:', circleId);
34
+ checkAndAdd();
45
35
 
46
- // 清理函数 - 移除圆形
47
36
  return () => {
48
- console.log('Circle useEffect cleanup - 移除圆形');
49
- if (circleIdRef.current && mapRef?.current) {
50
- mapRef.current.removeCircle(circleIdRef.current);
51
- console.log('✅ 圆形已移除:', circleIdRef.current);
37
+ if (circleIdRef.current) {
38
+ if (eventManager) {
39
+ eventManager.unregister(circleIdRef.current);
40
+ }
41
+ if (mapRef?.current) {
42
+ mapRef.current.removeCircle(circleIdRef.current);
43
+ }
52
44
  }
53
45
  };
54
46
  }, []);
55
47
 
56
-
57
- /**
58
- * 当Circle组件的props发生变化时,更新地图上的圆形覆盖物
59
- * 如果圆形ID和地图引用都存在,则调用地图实例的updateCircle方法更新圆形
60
- * 更新成功后会打印日志确认
61
- */
62
48
  React.useEffect(() => {
63
- console.log('Circle props 变化,更新圆形');
64
49
  if (circleIdRef.current && mapRef?.current) {
65
50
  mapRef.current.updateCircle(circleIdRef.current, props);
66
- console.log('✅ 圆形已更新:', circleIdRef.current);
67
51
  }
68
52
  }, [props.center, props.radius, props.fillColor, props.strokeColor, props.strokeWidth]);
69
53
 
70
- // 不渲染任何 UI
71
54
  return null;
72
55
  }
@@ -1,56 +1,83 @@
1
1
  import * as React from 'react';
2
- import { MapContext } from '../../ExpoGaodeMapView';
2
+ import { Image } from 'react-native';
3
+ import { MapContext, MarkerEventContext } from '../../ExpoGaodeMapView';
3
4
  import type { MarkerProps } from '../../types';
4
5
 
5
- /**
6
- * Marker 组件 - 用于在地图上显示标记点
7
- *
8
- * @param props - 标记点属性配置
9
- * @param props.position - 标记点坐标 [经度, 纬度]
10
- * @param props.title - 标记点标题
11
- * @param props.draggable - 标记点是否可拖动
12
- *
13
- * @remarks
14
- * 组件内部会自动处理标记点的添加、更新和移除
15
- * 当组件卸载时会自动移除对应的地图标记
16
- *
17
- * @note
18
- * 组件本身不渲染任何DOM元素,仅作为地图标记的逻辑容器
19
- */
20
6
  export default function Marker(props: MarkerProps) {
21
- const mapRef = React.useContext(MapContext);
22
- const markerIdRef = React.useRef<string>(`marker_${Date.now()}_${Math.random()}`);
23
-
24
- console.log('Marker 组件渲染,props:', props);
7
+ return <MarkerImperative {...props} />;
8
+ }
25
9
 
26
- // 添加标记
10
+ function MarkerImperative(props: MarkerProps) {
11
+ const mapRef = React.useContext(MapContext);
12
+ const eventManager = React.useContext(MarkerEventContext);
13
+ const markerIdRef = React.useRef<string | null>(null);
14
+ const propsRef = React.useRef(props);
15
+
16
+ React.useEffect(() => {
17
+ propsRef.current = props;
18
+ }, [props]);
19
+
27
20
  React.useEffect(() => {
28
- const markerId = markerIdRef.current;
21
+ const checkAndAdd = () => {
22
+ if (!mapRef?.current) {
23
+ setTimeout(checkAndAdd, 50);
24
+ return;
25
+ }
26
+
27
+ const markerId = `marker_${Date.now()}_${Math.random()}`;
28
+ markerIdRef.current = markerId;
29
+
30
+ if (eventManager) {
31
+ eventManager.register(markerId, {
32
+ onPress: props.onPress,
33
+ onDragStart: props.onDragStart,
34
+ onDrag: props.onDrag,
35
+ onDragEnd: props.onDragEnd,
36
+ });
37
+ }
38
+
39
+ const processedProps = { ...propsRef.current };
40
+ if (processedProps.icon && typeof processedProps.icon === 'number') {
41
+ const resolved = Image.resolveAssetSource(processedProps.icon);
42
+ processedProps.icon = resolved;
43
+ }
44
+
45
+ mapRef.current.addMarker(markerId, processedProps);
46
+ };
47
+
48
+ checkAndAdd();
29
49
 
30
- console.log('Marker useEffect - 添加标记到地图');
31
- mapRef?.current?.addMarker?.(markerId, props).then(() => {
32
- console.log('✅ 标记已添加:', markerId);
33
- }).catch((error: any) => {
34
- console.error('❌ 添加标记失败:', error);
35
- });
36
-
37
50
  return () => {
38
- console.log('Marker useEffect cleanup - 移除标记');
39
- mapRef?.current?.removeMarker?.(markerId).catch((error: any) => {
40
- console.error('❌ 移除标记失败:', error);
41
- });
51
+ if (markerIdRef.current) {
52
+ if (eventManager) {
53
+ eventManager.unregister(markerIdRef.current);
54
+ }
55
+ if (mapRef?.current) {
56
+ mapRef.current.removeMarker(markerIdRef.current);
57
+ }
58
+ }
42
59
  };
43
60
  }, []);
44
61
 
45
- // 监听 Props 变化,更新标记
46
62
  React.useEffect(() => {
47
- const markerId = markerIdRef.current;
48
-
49
- console.log('Marker props 变化,更新标记:', props);
50
- mapRef?.current?.updateMarker?.(markerId, props).catch((error: any) => {
51
- console.error('❌ 更新标记失败:', error);
52
- });
53
- }, [props.position, props.title, props.draggable]);
54
-
63
+ if (markerIdRef.current && mapRef?.current) {
64
+ const processedProps = { ...props };
65
+ if (processedProps.icon && typeof processedProps.icon === 'number') {
66
+ const resolved = Image.resolveAssetSource(processedProps.icon);
67
+ processedProps.icon = resolved;
68
+ }
69
+ mapRef.current.updateMarker(markerIdRef.current, processedProps);
70
+ }
71
+ }, [
72
+ props.position?.latitude,
73
+ props.position?.longitude,
74
+ props.title,
75
+ props.draggable,
76
+ props.icon,
77
+ props.iconWidth,
78
+ props.iconHeight,
79
+ props.pinColor
80
+ ]);
81
+
55
82
  return null;
56
83
  }