expo-gaode-map 0.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 (132) hide show
  1. package/.eslintrc.js +5 -0
  2. package/PUBLISHING.md +244 -0
  3. package/README.md +990 -0
  4. package/android/build.gradle +48 -0
  5. package/android/src/main/AndroidManifest.xml +40 -0
  6. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +455 -0
  7. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +337 -0
  8. package/android/src/main/java/expo/modules/gaodemap/managers/CameraManager.kt +128 -0
  9. package/android/src/main/java/expo/modules/gaodemap/managers/OverlayManager.kt +324 -0
  10. package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +122 -0
  11. package/android/src/main/java/expo/modules/gaodemap/modules/LocationManager.kt +247 -0
  12. package/android/src/main/java/expo/modules/gaodemap/modules/SDKInitializer.kt +45 -0
  13. package/android/src/main/java/expo/modules/gaodemap/overlays/CircleView.kt +151 -0
  14. package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +127 -0
  15. package/android/src/main/java/expo/modules/gaodemap/overlays/HeatMapView.kt +97 -0
  16. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +204 -0
  17. package/android/src/main/java/expo/modules/gaodemap/overlays/MultiPointView.kt +103 -0
  18. package/android/src/main/java/expo/modules/gaodemap/overlays/PolygonView.kt +114 -0
  19. package/android/src/main/java/expo/modules/gaodemap/overlays/PolylineView.kt +138 -0
  20. package/build/ExpoGaodeMap.types.d.ts +24 -0
  21. package/build/ExpoGaodeMap.types.d.ts.map +1 -0
  22. package/build/ExpoGaodeMap.types.js +14 -0
  23. package/build/ExpoGaodeMap.types.js.map +1 -0
  24. package/build/ExpoGaodeMapModule.d.ts +7 -0
  25. package/build/ExpoGaodeMapModule.d.ts.map +1 -0
  26. package/build/ExpoGaodeMapModule.js +14 -0
  27. package/build/ExpoGaodeMapModule.js.map +1 -0
  28. package/build/ExpoGaodeMapView.d.ts +31 -0
  29. package/build/ExpoGaodeMapView.d.ts.map +1 -0
  30. package/build/ExpoGaodeMapView.js +141 -0
  31. package/build/ExpoGaodeMapView.js.map +1 -0
  32. package/build/components/overlays/Circle.d.ts +18 -0
  33. package/build/components/overlays/Circle.d.ts.map +1 -0
  34. package/build/components/overlays/Circle.js +63 -0
  35. package/build/components/overlays/Circle.js.map +1 -0
  36. package/build/components/overlays/Cluster.d.ts +22 -0
  37. package/build/components/overlays/Cluster.d.ts.map +1 -0
  38. package/build/components/overlays/Cluster.js +35 -0
  39. package/build/components/overlays/Cluster.js.map +1 -0
  40. package/build/components/overlays/HeatMap.d.ts +21 -0
  41. package/build/components/overlays/HeatMap.d.ts.map +1 -0
  42. package/build/components/overlays/HeatMap.js +34 -0
  43. package/build/components/overlays/HeatMap.js.map +1 -0
  44. package/build/components/overlays/Marker.d.ts +17 -0
  45. package/build/components/overlays/Marker.d.ts.map +1 -0
  46. package/build/components/overlays/Marker.js +57 -0
  47. package/build/components/overlays/Marker.js.map +1 -0
  48. package/build/components/overlays/MultiPoint.d.ts +21 -0
  49. package/build/components/overlays/MultiPoint.d.ts.map +1 -0
  50. package/build/components/overlays/MultiPoint.js +34 -0
  51. package/build/components/overlays/MultiPoint.js.map +1 -0
  52. package/build/components/overlays/Polygon.d.ts +22 -0
  53. package/build/components/overlays/Polygon.d.ts.map +1 -0
  54. package/build/components/overlays/Polygon.js +100 -0
  55. package/build/components/overlays/Polygon.js.map +1 -0
  56. package/build/components/overlays/Polyline.d.ts +20 -0
  57. package/build/components/overlays/Polyline.d.ts.map +1 -0
  58. package/build/components/overlays/Polyline.js +60 -0
  59. package/build/components/overlays/Polyline.js.map +1 -0
  60. package/build/components/overlays/index.d.ts +8 -0
  61. package/build/components/overlays/index.d.ts.map +1 -0
  62. package/build/components/overlays/index.js +18 -0
  63. package/build/components/overlays/index.js.map +1 -0
  64. package/build/index.d.ts +10 -0
  65. package/build/index.d.ts.map +1 -0
  66. package/build/index.js +28 -0
  67. package/build/index.js.map +1 -0
  68. package/build/modules/AMapLocation.d.ts +58 -0
  69. package/build/modules/AMapLocation.d.ts.map +1 -0
  70. package/build/modules/AMapLocation.js +141 -0
  71. package/build/modules/AMapLocation.js.map +1 -0
  72. package/build/modules/AMapSDK.d.ts +27 -0
  73. package/build/modules/AMapSDK.d.ts.map +1 -0
  74. package/build/modules/AMapSDK.js +43 -0
  75. package/build/modules/AMapSDK.js.map +1 -0
  76. package/build/modules/AMapView.d.ts +39 -0
  77. package/build/modules/AMapView.d.ts.map +1 -0
  78. package/build/modules/AMapView.js +61 -0
  79. package/build/modules/AMapView.js.map +1 -0
  80. package/build/types/common.types.d.ts +133 -0
  81. package/build/types/common.types.d.ts.map +1 -0
  82. package/build/types/common.types.js +31 -0
  83. package/build/types/common.types.js.map +1 -0
  84. package/build/types/index.d.ts +12 -0
  85. package/build/types/index.d.ts.map +1 -0
  86. package/build/types/index.js +17 -0
  87. package/build/types/index.js.map +1 -0
  88. package/build/types/location.types.d.ts +306 -0
  89. package/build/types/location.types.d.ts.map +1 -0
  90. package/build/types/location.types.js +93 -0
  91. package/build/types/location.types.js.map +1 -0
  92. package/build/types/map-view.types.d.ts +213 -0
  93. package/build/types/map-view.types.d.ts.map +1 -0
  94. package/build/types/map-view.types.js +6 -0
  95. package/build/types/map-view.types.js.map +1 -0
  96. package/build/types/overlays.types.d.ts +296 -0
  97. package/build/types/overlays.types.d.ts.map +1 -0
  98. package/build/types/overlays.types.js +6 -0
  99. package/build/types/overlays.types.js.map +1 -0
  100. package/build/types/sdk.types.d.ts +113 -0
  101. package/build/types/sdk.types.d.ts.map +1 -0
  102. package/build/types/sdk.types.js +6 -0
  103. package/build/types/sdk.types.js.map +1 -0
  104. package/docs/followUserLocation.md +186 -0
  105. package/expo-module.config.json +9 -0
  106. package/ios/ExpoGaodeMap.podspec +29 -0
  107. package/ios/ExpoGaodeMapModule.swift +48 -0
  108. package/ios/ExpoGaodeMapView.swift +38 -0
  109. package/package.json +45 -0
  110. package/src/ExpoGaodeMap.types.ts +68 -0
  111. package/src/ExpoGaodeMapModule.ts +21 -0
  112. package/src/ExpoGaodeMapView.tsx +151 -0
  113. package/src/components/overlays/Circle.tsx +73 -0
  114. package/src/components/overlays/Cluster.tsx +38 -0
  115. package/src/components/overlays/HeatMap.tsx +37 -0
  116. package/src/components/overlays/Marker.tsx +66 -0
  117. package/src/components/overlays/MultiPoint.tsx +37 -0
  118. package/src/components/overlays/Polygon.tsx +107 -0
  119. package/src/components/overlays/Polyline.tsx +69 -0
  120. package/src/components/overlays/index.ts +18 -0
  121. package/src/index.ts +55 -0
  122. package/src/modules/AMapLocation.ts +164 -0
  123. package/src/modules/AMapSDK.ts +48 -0
  124. package/src/modules/AMapView.ts +68 -0
  125. package/src/types/README.md +186 -0
  126. package/src/types/common.types.ts +155 -0
  127. package/src/types/index.ts +74 -0
  128. package/src/types/location.types.ts +364 -0
  129. package/src/types/map-view.types.ts +249 -0
  130. package/src/types/overlays.types.ts +346 -0
  131. package/src/types/sdk.types.ts +128 -0
  132. package/tsconfig.json +9 -0
package/README.md ADDED
@@ -0,0 +1,990 @@
1
+ # expo-gaode-map
2
+
3
+ 一个功能完整的高德地图 React Native 组件库,**基于 Expo Modules 开发**,提供地图显示、定位、覆盖物等功能:
4
+ - Android: [高德地图 Android SDK](https://lbs.amap.com/api/android-sdk/summary)
5
+ - iOS: [高德地图 iOS SDK](https://lbs.amap.com/api/ios-sdk/summary) (开发中)
6
+
7
+ > 💡 本组件使用 [Expo Modules API](https://docs.expo.dev/modules/overview/) 构建,提供了类型安全的原生模块接口和优秀的开发体验。
8
+
9
+ ## ✨ 特性
10
+
11
+ - ✅ 完整的地图功能(多种地图类型、手势控制、相机操作)
12
+ - ✅ 精准定位(连续定位、单次定位、坐标转换)
13
+ - ✅ 丰富的覆盖物(Circle、Marker、Polyline、Polygon)
14
+ - ✅ 完整的 TypeScript 类型定义(零 any 类型)
15
+ - ✅ 模块化架构设计
16
+ - ✅ 同时支持声明式组件和命令式 API
17
+ - ✅ 跨平台支持(Android 完整支持,iOS 开发中)
18
+ - ✅ 支持自定义样式和事件监听
19
+
20
+ ## 📦 安装
21
+
22
+ ```bash
23
+ npm install expo-gaode-map
24
+ # 或
25
+ yarn add expo-gaode-map
26
+ # 或
27
+ pnpm add expo-gaode-map
28
+ ```
29
+
30
+ ### Expo 项目
31
+
32
+ 如果你使用的是 Expo 管理的项目(使用 `expo prebuild` 或开发构建),安装后需要重新构建原生代码:
33
+
34
+ ```bash
35
+ # 使用 EAS Build
36
+ eas build --platform android
37
+
38
+ # 或使用本地构建
39
+ npx expo prebuild
40
+ npx expo run:android
41
+ ```
42
+
43
+ ### 纯 React Native 项目
44
+
45
+ 对于纯 React Native 项目(通过 `react-native init` 创建),确保已安装 `expo` 包作为依赖:
46
+
47
+ ```bash
48
+ npm install expo
49
+ # 然后重新构建应用
50
+ npx react-native run-android
51
+ ```
52
+
53
+ ## 🚀 快速开始
54
+
55
+ ### 1. 获取高德地图 API Key
56
+
57
+ 前往 [高德开放平台](https://lbs.amap.com/) 注册并创建应用,获取 API Key。
58
+
59
+ ### 2. 配置 API Key
60
+
61
+ 在 `app.json` 中配置(推荐):
62
+
63
+ ```json
64
+ {
65
+ "expo": {
66
+ "android": {
67
+ "config": {
68
+ "gaodeMapApiKey": "your-android-api-key"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ### 3. 初始化 SDK
76
+
77
+ ```tsx
78
+ import { useEffect } from 'react';
79
+ import { initSDK } from 'expo-gaode-map';
80
+
81
+ export default function App() {
82
+ useEffect(() => {
83
+ initSDK({
84
+ androidKey: 'your-android-api-key',
85
+ iosKey: 'your-ios-api-key', // iOS 暂不支持
86
+ });
87
+ }, []);
88
+
89
+ return (
90
+ // 你的应用内容
91
+ );
92
+ }
93
+ ```
94
+
95
+ ### 4. 使用地图组件
96
+
97
+ ```tsx
98
+ import { MapView } from 'expo-gaode-map';
99
+
100
+ export default function MapScreen() {
101
+ return (
102
+ <MapView
103
+ style={{ flex: 1 }}
104
+ initialCameraPosition={{
105
+ target: { latitude: 39.9, longitude: 116.4 },
106
+ zoom: 10,
107
+ }}
108
+ myLocationEnabled={true}
109
+ onLoad={() => console.log('地图加载完成')}
110
+ />
111
+ );
112
+ }
113
+ ```
114
+
115
+ ## 📚 核心功能
116
+
117
+ ### 🗺️ 地图显示
118
+
119
+ #### 基础用法
120
+
121
+ ```tsx
122
+ import { MapView } from 'expo-gaode-map';
123
+
124
+ <MapView
125
+ style={{ flex: 1 }}
126
+ mapType={0} // 0: 标准, 1: 卫星, 2: 夜间, 3: 导航, 4: 公交
127
+ initialCameraPosition={{
128
+ target: { latitude: 39.9, longitude: 116.4 },
129
+ zoom: 15,
130
+ tilt: 30, // 倾斜角度 (0-60)
131
+ bearing: 0, // 旋转角度 (0-360)
132
+ }}
133
+ myLocationEnabled={true}
134
+ followUserLocation={false} // 是否跟随用户位置
135
+ onPress={(e) => console.log('点击地图', e)}
136
+ onLongPress={(e) => console.log('长按地图', e)}
137
+ onLoad={() => console.log('地图加载完成')}
138
+ />
139
+ ```
140
+
141
+ #### 相机控制
142
+
143
+ 使用 Ref 调用地图方法:
144
+
145
+ ```tsx
146
+ import { useRef } from 'react';
147
+ import { MapView, type MapViewRef } from 'expo-gaode-map';
148
+
149
+ function MapWithControls() {
150
+ const mapRef = useRef<MapViewRef>(null);
151
+
152
+ const moveToBeijing = async () => {
153
+ await mapRef.current?.moveCamera(
154
+ {
155
+ target: { latitude: 39.9, longitude: 116.4 },
156
+ zoom: 15,
157
+ },
158
+ 1000 // 动画时长(毫秒)
159
+ );
160
+ };
161
+
162
+ const zoomIn = async () => {
163
+ await mapRef.current?.setZoom(16, true);
164
+ };
165
+
166
+ return (
167
+ <MapView
168
+ ref={mapRef}
169
+ style={{ flex: 1 }}
170
+ />
171
+ );
172
+ }
173
+ ```
174
+
175
+ ### 📍 定位功能
176
+
177
+ #### 开始/停止定位
178
+
179
+ ```tsx
180
+ import { start, stop, isStarted } from 'expo-gaode-map';
181
+
182
+ // 开始连续定位
183
+ start();
184
+
185
+ // 停止定位
186
+ stop();
187
+
188
+ // 检查定位状态
189
+ const started = await isStarted();
190
+ ```
191
+
192
+ #### 获取当前位置
193
+
194
+ ```tsx
195
+ import { getCurrentLocation } from 'expo-gaode-map';
196
+
197
+ const location = await getCurrentLocation();
198
+ console.log(location);
199
+ // {
200
+ // latitude: 39.9042,
201
+ // longitude: 116.4074,
202
+ // accuracy: 10,
203
+ // altitude: 50,
204
+ // bearing: 90,
205
+ // speed: 5,
206
+ // address: '北京市朝阳区...',
207
+ // province: '北京市',
208
+ // city: '北京市',
209
+ // district: '朝阳区',
210
+ // street: '建国路',
211
+ // ...
212
+ // }
213
+ ```
214
+
215
+ #### 定位配置
216
+
217
+ ```tsx
218
+ import {
219
+ setLocatingWithReGeocode,
220
+ setLocationMode,
221
+ setInterval,
222
+ } from 'expo-gaode-map';
223
+
224
+ // 是否返回逆地理信息(地址)
225
+ setLocatingWithReGeocode(true);
226
+
227
+ // 定位模式: 0-高精度, 1-低功耗, 2-仅设备
228
+ setLocationMode(0);
229
+
230
+ // 定位间隔(毫秒)
231
+ setInterval(2000);
232
+ ```
233
+
234
+ #### 监听定位更新
235
+
236
+ ```tsx
237
+ import { useEffect } from 'react';
238
+ import { addLocationListener } from 'expo-gaode-map';
239
+
240
+ function LocationTracking() {
241
+ useEffect(() => {
242
+ const subscription = addLocationListener((location) => {
243
+ console.log('位置更新:', location);
244
+ });
245
+
246
+ return () => subscription.remove();
247
+ }, []);
248
+
249
+ return (
250
+ // 你的组件
251
+ );
252
+ }
253
+ ```
254
+
255
+ ### 🎨 覆盖物
256
+
257
+ #### Circle (圆形)
258
+
259
+ **声明式用法:**
260
+
261
+ ```tsx
262
+ import { MapView, Circle } from 'expo-gaode-map';
263
+
264
+ <MapView style={{ flex: 1 }}>
265
+ <Circle
266
+ center={{ latitude: 39.9, longitude: 116.4 }}
267
+ radius={1000} // 半径(米)
268
+ fillColor="#8800FF00" // 填充颜色(ARGB 格式)
269
+ strokeColor="#FFFF0000" // 边框颜色
270
+ strokeWidth={2} // 边框宽度
271
+ onPress={() => console.log('点击圆形')}
272
+ />
273
+ </MapView>
274
+ ```
275
+
276
+ **命令式用法:**
277
+
278
+ ```tsx
279
+ const mapRef = useRef<MapViewRef>(null);
280
+
281
+ // 添加圆形
282
+ await mapRef.current?.addCircle('circle1', {
283
+ center: { latitude: 39.9, longitude: 116.4 },
284
+ radius: 1000,
285
+ fillColor: 0x8800FF00,
286
+ strokeColor: 0xFFFF0000,
287
+ strokeWidth: 2,
288
+ });
289
+
290
+ // 更新圆形
291
+ await mapRef.current?.updateCircle('circle1', {
292
+ radius: 2000,
293
+ fillColor: 0x880000FF,
294
+ });
295
+
296
+ // 移除圆形
297
+ await mapRef.current?.removeCircle('circle1');
298
+ ```
299
+
300
+ #### Marker (标记点)
301
+
302
+ **声明式用法:**
303
+
304
+ ```tsx
305
+ import { MapView, Marker } from 'expo-gaode-map';
306
+
307
+ <MapView style={{ flex: 1 }}>
308
+ <Marker
309
+ position={{ latitude: 39.9, longitude: 116.4 }}
310
+ title="标题"
311
+ description="描述信息"
312
+ draggable={true}
313
+ onPress={() => console.log('点击标记')}
314
+ onDragStart={() => console.log('开始拖动')}
315
+ onDrag={(e) => console.log('拖动中', e)}
316
+ onDragEnd={(e) => console.log('拖动结束', e)}
317
+ />
318
+ </MapView>
319
+ ```
320
+
321
+ **命令式用法:**
322
+
323
+ ```tsx
324
+ await mapRef.current?.addMarker('marker1', {
325
+ position: { latitude: 39.9, longitude: 116.4 },
326
+ title: '标题',
327
+ draggable: true,
328
+ });
329
+
330
+ await mapRef.current?.updateMarker('marker1', {
331
+ position: { latitude: 40.0, longitude: 116.5 },
332
+ });
333
+
334
+ await mapRef.current?.removeMarker('marker1');
335
+ ```
336
+
337
+ #### Polyline (折线)
338
+
339
+ **声明式用法:**
340
+
341
+ ```tsx
342
+ import { MapView, Polyline } from 'expo-gaode-map';
343
+
344
+ <MapView style={{ flex: 1 }}>
345
+ <Polyline
346
+ points={[
347
+ { latitude: 39.9, longitude: 116.4 },
348
+ { latitude: 39.95, longitude: 116.45 },
349
+ { latitude: 40.0, longitude: 116.5 },
350
+ ]}
351
+ strokeWidth={5}
352
+ strokeColor="#FF0000FF"
353
+ onPress={() => console.log('点击折线')}
354
+ />
355
+ </MapView>
356
+ ```
357
+
358
+ **命令式用法:**
359
+
360
+ ```tsx
361
+ await mapRef.current?.addPolyline('polyline1', {
362
+ points: [
363
+ { latitude: 39.9, longitude: 116.4 },
364
+ { latitude: 40.0, longitude: 116.5 },
365
+ ],
366
+ width: 5,
367
+ color: 0xFFFF0000,
368
+ });
369
+
370
+ await mapRef.current?.updatePolyline('polyline1', {
371
+ width: 10,
372
+ color: 0xFF0000FF,
373
+ });
374
+
375
+ await mapRef.current?.removePolyline('polyline1');
376
+ ```
377
+
378
+ #### Polygon (多边形)
379
+
380
+ **声明式用法:**
381
+
382
+ ```tsx
383
+ import { MapView, Polygon } from 'expo-gaode-map';
384
+
385
+ <MapView style={{ flex: 1 }}>
386
+ <Polygon
387
+ points={[
388
+ { latitude: 39.9, longitude: 116.3 },
389
+ { latitude: 39.9, longitude: 116.4 },
390
+ { latitude: 39.8, longitude: 116.4 },
391
+ ]}
392
+ fillColor="#8800FF00"
393
+ strokeColor="#FFFF0000"
394
+ strokeWidth={2}
395
+ onPress={() => console.log('点击多边形')}
396
+ />
397
+ </MapView>
398
+ ```
399
+
400
+ **命令式用法:**
401
+
402
+ ```tsx
403
+ await mapRef.current?.addPolygon('polygon1', {
404
+ points: [
405
+ { latitude: 39.9, longitude: 116.3 },
406
+ { latitude: 39.9, longitude: 116.4 },
407
+ { latitude: 39.8, longitude: 116.4 },
408
+ ],
409
+ fillColor: 0x8800FF00,
410
+ strokeColor: 0xFFFF0000,
411
+ strokeWidth: 2,
412
+ });
413
+
414
+ await mapRef.current?.updatePolygon('polygon1', {
415
+ fillColor: 0x880000FF,
416
+ });
417
+
418
+ await mapRef.current?.removePolygon('polygon1');
419
+ ```
420
+
421
+ ## 📖 API 文档
422
+
423
+ ### MapView Props
424
+
425
+ #### 基础配置
426
+
427
+ | 属性 | 类型 | 默认值 | 说明 |
428
+ |------|------|--------|------|
429
+ | `mapType` | `MapType` | `0` | 地图类型(0: 标准, 1: 卫星, 2: 夜间, 3: 导航, 4: 公交) |
430
+ | `initialCameraPosition` | `CameraPosition` | - | 初始相机位置 |
431
+ | `style` | `ViewStyle` | - | 组件样式 |
432
+
433
+ #### 定位相关
434
+
435
+ | 属性 | 类型 | 默认值 | 说明 |
436
+ |------|------|--------|------|
437
+ | `myLocationEnabled` | `boolean` | `false` | 是否显示定位点 |
438
+ | `followUserLocation` | `boolean` | `false` | 是否跟随用户位置(开启后地图会自动移动) |
439
+
440
+ #### 控件显示
441
+
442
+ | 属性 | 类型 | 默认值 | 说明 |
443
+ |------|------|--------|------|
444
+ | `zoomControlsEnabled` | `boolean` | `true` | 是否显示缩放控件(Android) |
445
+ | `compassEnabled` | `boolean` | `true` | 是否显示指南针 |
446
+ | `scaleControlsEnabled` | `boolean` | `true` | 是否显示比例尺 |
447
+
448
+ #### 手势控制
449
+
450
+ | 属性 | 类型 | 默认值 | 说明 |
451
+ |------|------|--------|------|
452
+ | `zoomGesturesEnabled` | `boolean` | `true` | 是否启用缩放手势 |
453
+ | `scrollGesturesEnabled` | `boolean` | `true` | 是否启用滑动手势 |
454
+ | `rotateGesturesEnabled` | `boolean` | `true` | 是否启用旋转手势 |
455
+ | `tiltGesturesEnabled` | `boolean` | `true` | 是否启用倾斜手势 |
456
+
457
+ #### 图层显示
458
+
459
+ | 属性 | 类型 | 默认值 | 说明 |
460
+ |------|------|--------|------|
461
+ | `trafficEnabled` | `boolean` | `false` | 是否显示路况信息 |
462
+ | `buildingsEnabled` | `boolean` | `true` | 是否显示3D建筑 |
463
+ | `indoorViewEnabled` | `boolean` | `false` | 是否显示室内地图 |
464
+
465
+ #### 事件回调
466
+
467
+ | 事件 | 参数 | 说明 |
468
+ |------|------|------|
469
+ | `onPress` | `(event: LatLng) => void` | 点击地图事件 |
470
+ | `onLongPress` | `(event: LatLng) => void` | 长按地图事件 |
471
+ | `onLoad` | `() => void` | 地图加载完成事件 |
472
+
473
+ ### MapView 方法(通过 Ref 调用)
474
+
475
+ ```tsx
476
+ interface MapViewRef {
477
+ // 相机控制
478
+ moveCamera(position: CameraPosition, duration?: number): Promise<void>;
479
+ setCenter(center: LatLng, animated?: boolean): Promise<void>;
480
+ setZoom(zoom: number, animated?: boolean): Promise<void>;
481
+ getCameraPosition(): Promise<CameraPosition>;
482
+ getLatLng(point: Point): Promise<LatLng>;
483
+
484
+ // Circle 操作
485
+ addCircle(id: string, props: CircleProps): Promise<void>;
486
+ removeCircle(id: string): Promise<void>;
487
+ updateCircle(id: string, props: Partial<CircleProps>): Promise<void>;
488
+
489
+ // Marker 操作
490
+ addMarker(id: string, props: MarkerProps): Promise<void>;
491
+ removeMarker(id: string): Promise<void>;
492
+ updateMarker(id: string, props: Partial<MarkerProps>): Promise<void>;
493
+
494
+ // Polyline 操作
495
+ addPolyline(id: string, props: PolylineProps): Promise<void>;
496
+ removePolyline(id: string): Promise<void>;
497
+ updatePolyline(id: string, props: Partial<PolylineProps>): Promise<void>;
498
+
499
+ // Polygon 操作
500
+ addPolygon(id: string, props: PolygonProps): Promise<void>;
501
+ removePolygon(id: string): Promise<void>;
502
+ updatePolygon(id: string, props: Partial<PolygonProps>): Promise<void>;
503
+ }
504
+ ```
505
+
506
+ ### 定位 API
507
+
508
+ #### 定位控制
509
+
510
+ | 方法 | 参数 | 返回值 | 说明 |
511
+ |------|------|--------|------|
512
+ | `initSDK` | `{androidKey, iosKey}` | `void` | 初始化 SDK |
513
+ | `start` | - | `void` | 开始连续定位 |
514
+ | `stop` | - | `void` | 停止定位 |
515
+ | `isStarted` | - | `Promise<boolean>` | 检查是否正在定位 |
516
+ | `getCurrentLocation` | - | `Promise<Location>` | 获取当前位置(单次定位) |
517
+
518
+ #### 定位配置
519
+
520
+ | 方法 | 参数 | 返回值 | 说明 |
521
+ |------|------|--------|------|
522
+ | `setLocatingWithReGeocode` | `boolean` | `void` | 是否返回逆地理信息 |
523
+ | `setLocationMode` | `0 \| 1 \| 2` | `void` | 定位模式(0: 高精度, 1: 低功耗, 2: 仅设备) |
524
+ | `setInterval` | `number` | `void` | 定位间隔(毫秒) |
525
+ | `setOnceLocation` | `boolean` | `void` | 是否单次定位 |
526
+ | `setSensorEnable` | `boolean` | `void` | 是否使用设备传感器 |
527
+ | `setWifiScan` | `boolean` | `void` | 是否允许 WiFi 扫描 |
528
+ | `setGpsFirst` | `boolean` | `void` | 是否 GPS 优先 |
529
+ | `setGeoLanguage` | `string` | `void` | 逆地理语言('zh' 或 'en') |
530
+
531
+ #### 坐标转换
532
+
533
+ | 方法 | 参数 | 返回值 | 说明 |
534
+ |------|------|--------|------|
535
+ | `coordinateConvert` | `coordinate, type` | `Promise<LatLng>` | 坐标转换为高德坐标 |
536
+
537
+ ### 类型定义
538
+
539
+ #### MapType (地图类型)
540
+
541
+ ```typescript
542
+ enum MapType {
543
+ NORMAL = 0, // 标准地图
544
+ SATELLITE = 1, // 卫星地图
545
+ NIGHT = 2, // 夜间地图
546
+ NAVI = 3, // 导航地图
547
+ BUS = 4, // 公交地图
548
+ }
549
+ ```
550
+
551
+ #### CameraPosition (相机位置)
552
+
553
+ ```typescript
554
+ interface CameraPosition {
555
+ target: LatLng; // 目标位置
556
+ zoom: number; // 缩放级别 (3-20)
557
+ tilt?: number; // 倾斜角度 (0-60)
558
+ bearing?: number; // 旋转角度 (0-360)
559
+ }
560
+ ```
561
+
562
+ #### LatLng (经纬度)
563
+
564
+ ```typescript
565
+ interface LatLng {
566
+ latitude: number; // 纬度
567
+ longitude: number; // 经度
568
+ }
569
+ ```
570
+
571
+ #### Location (定位信息)
572
+
573
+ ```typescript
574
+ interface Location {
575
+ // 基础位置信息
576
+ latitude: number; // 纬度
577
+ longitude: number; // 经度
578
+ accuracy: number; // 精度(米)
579
+ altitude: number; // 海拔(米)
580
+ bearing: number; // 方向角(度)
581
+ speed: number; // 速度(米/秒)
582
+
583
+ // 地址信息(需要开启逆地理)
584
+ address?: string; // 详细地址
585
+ province?: string; // 省份
586
+ city?: string; // 城市
587
+ district?: string; // 区县
588
+ street?: string; // 街道
589
+ streetNumber?: string; // 门牌号
590
+ country?: string; // 国家
591
+ cityCode?: string; // 城市编码
592
+ adCode?: string; // 区域编码
593
+ poiName?: string; // POI 名称
594
+ aoiName?: string; // AOI 名称
595
+
596
+ // 其他信息
597
+ provider?: string; // 定位提供者
598
+ timestamp?: number; // 时间戳
599
+ }
600
+ ```
601
+
602
+ ## 🎯 完整示例
603
+
604
+ ### 基础地图应用
605
+
606
+ ```tsx
607
+ import React, { useRef, useEffect } from 'react';
608
+ import { View, StyleSheet, Button } from 'react-native';
609
+ import {
610
+ MapView,
611
+ initSDK,
612
+ Circle,
613
+ Marker,
614
+ Polyline,
615
+ Polygon,
616
+ type MapViewRef
617
+ } from 'expo-gaode-map';
618
+
619
+ export default function App() {
620
+ const mapRef = useRef<MapViewRef>(null);
621
+
622
+ useEffect(() => {
623
+ initSDK({
624
+ androidKey: 'your-android-api-key',
625
+ });
626
+ }, []);
627
+
628
+ const handleMoveCamera = async () => {
629
+ await mapRef.current?.moveCamera(
630
+ {
631
+ target: { latitude: 40.0, longitude: 116.5 },
632
+ zoom: 15,
633
+ },
634
+ 1000
635
+ );
636
+ };
637
+
638
+ return (
639
+ <View style={styles.container}>
640
+ <MapView
641
+ ref={mapRef}
642
+ style={styles.map}
643
+ initialCameraPosition={{
644
+ target: { latitude: 39.9, longitude: 116.4 },
645
+ zoom: 10,
646
+ }}
647
+ myLocationEnabled={true}
648
+ followUserLocation={false}
649
+ trafficEnabled={true}
650
+ onPress={(e) => console.log('点击地图', e)}
651
+ onLoad={() => console.log('地图加载完成')}
652
+ >
653
+ {/* 圆形覆盖物 */}
654
+ <Circle
655
+ center={{ latitude: 39.9, longitude: 116.4 }}
656
+ radius={1000}
657
+ fillColor="#8800FF00"
658
+ strokeColor="#FFFF0000"
659
+ strokeWidth={2}
660
+ />
661
+
662
+ {/* 标记点 */}
663
+ <Marker
664
+ position={{ latitude: 39.95, longitude: 116.45 }}
665
+ title="这是一个标记"
666
+ draggable={true}
667
+ />
668
+
669
+ {/* 折线 */}
670
+ <Polyline
671
+ points={[
672
+ { latitude: 39.9, longitude: 116.4 },
673
+ { latitude: 39.95, longitude: 116.45 },
674
+ { latitude: 40.0, longitude: 116.5 },
675
+ ]}
676
+ strokeWidth={5}
677
+ strokeColor="#FF0000FF"
678
+ />
679
+
680
+ {/* 多边形 */}
681
+ <Polygon
682
+ points={[
683
+ { latitude: 39.85, longitude: 116.35 },
684
+ { latitude: 39.85, longitude: 116.45 },
685
+ { latitude: 39.75, longitude: 116.40 },
686
+ ]}
687
+ fillColor="#880000FF"
688
+ strokeColor="#FFFF0000"
689
+ strokeWidth={2}
690
+ />
691
+ </MapView>
692
+
693
+ <View style={styles.controls}>
694
+ <Button title="移动相机" onPress={handleMoveCamera} />
695
+ </View>
696
+ </View>
697
+ );
698
+ }
699
+
700
+ const styles = StyleSheet.create({
701
+ container: {
702
+ flex: 1,
703
+ },
704
+ map: {
705
+ flex: 1,
706
+ },
707
+ controls: {
708
+ position: 'absolute',
709
+ bottom: 20,
710
+ left: 20,
711
+ right: 20,
712
+ },
713
+ });
714
+ ```
715
+
716
+ ### 定位追踪应用
717
+
718
+ ```tsx
719
+ import React, { useEffect, useState } from 'react';
720
+ import { View, Text, Button, StyleSheet } from 'react-native';
721
+ import {
722
+ MapView,
723
+ initSDK,
724
+ start,
725
+ stop,
726
+ getCurrentLocation,
727
+ addLocationListener,
728
+ setLocatingWithReGeocode,
729
+ setLocationMode,
730
+ setInterval,
731
+ type Location,
732
+ } from 'expo-gaode-map';
733
+
734
+ export default function LocationApp() {
735
+ const [location, setLocation] = useState<Location | null>(null);
736
+ const [isTracking, setIsTracking] = useState(false);
737
+
738
+ useEffect(() => {
739
+ // 初始化 SDK
740
+ initSDK({
741
+ androidKey: 'your-android-api-key',
742
+ });
743
+
744
+ // 配置定位参数
745
+ setLocatingWithReGeocode(true); // 返回地址信息
746
+ setLocationMode(0); // 高精度模式
747
+ setInterval(2000); // 2秒更新一次
748
+
749
+ // 监听位置更新
750
+ const subscription = addLocationListener((loc) => {
751
+ console.log('位置更新:', loc);
752
+ setLocation(loc);
753
+ });
754
+
755
+ return () => subscription.remove();
756
+ }, []);
757
+
758
+ const handleStartTracking = () => {
759
+ start();
760
+ setIsTracking(true);
761
+ };
762
+
763
+ const handleStopTracking = () => {
764
+ stop();
765
+ setIsTracking(false);
766
+ };
767
+
768
+ const handleGetLocation = async () => {
769
+ try {
770
+ const loc = await getCurrentLocation();
771
+ setLocation(loc);
772
+ } catch (error) {
773
+ console.error('获取位置失败:', error);
774
+ }
775
+ };
776
+
777
+ return (
778
+ <View style={styles.container}>
779
+ <MapView
780
+ style={styles.map}
781
+ myLocationEnabled={true}
782
+ followUserLocation={isTracking}
783
+ initialCameraPosition={{
784
+ target: {
785
+ latitude: location?.latitude || 39.9,
786
+ longitude: location?.longitude || 116.4
787
+ },
788
+ zoom: 15,
789
+ }}
790
+ />
791
+
792
+ {location && (
793
+ <View style={styles.info}>
794
+ <Text style={styles.infoText}>
795
+ 纬度: {location.latitude.toFixed(6)}
796
+ </Text>
797
+ <Text style={styles.infoText}>
798
+ 经度: {location.longitude.toFixed(6)}
799
+ </Text>
800
+ <Text style={styles.infoText}>
801
+ 精度: {location.accuracy.toFixed(2)} 米
802
+ </Text>
803
+ {location.address && (
804
+ <Text style={styles.infoText}>
805
+ 地址: {location.address}
806
+ </Text>
807
+ )}
808
+ </View>
809
+ )}
810
+
811
+ <View style={styles.controls}>
812
+ <Button
813
+ title="获取位置"
814
+ onPress={handleGetLocation}
815
+ />
816
+ <View style={{ height: 10 }} />
817
+ <Button
818
+ title={isTracking ? '停止追踪' : '开始追踪'}
819
+ onPress={isTracking ? handleStopTracking : handleStartTracking}
820
+ color={isTracking ? '#FF3B30' : '#007AFF'}
821
+ />
822
+ </View>
823
+ </View>
824
+ );
825
+ }
826
+
827
+ const styles = StyleSheet.create({
828
+ container: {
829
+ flex: 1,
830
+ },
831
+ map: {
832
+ flex: 1,
833
+ },
834
+ info: {
835
+ position: 'absolute',
836
+ top: 50,
837
+ left: 20,
838
+ right: 20,
839
+ backgroundColor: 'white',
840
+ padding: 15,
841
+ borderRadius: 10,
842
+ shadowColor: '#000',
843
+ shadowOffset: { width: 0, height: 2 },
844
+ shadowOpacity: 0.25,
845
+ shadowRadius: 3.84,
846
+ elevation: 5,
847
+ },
848
+ infoText: {
849
+ fontSize: 14,
850
+ marginBottom: 5,
851
+ color: '#333',
852
+ },
853
+ controls: {
854
+ position: 'absolute',
855
+ bottom: 30,
856
+ left: 20,
857
+ right: 20,
858
+ },
859
+ });
860
+ ```
861
+
862
+ ## 🎨 高级用法
863
+
864
+ ### followUserLocation 详解
865
+
866
+ `followUserLocation` 控制地图是否自动跟随用户位置移动:
867
+
868
+ **浏览模式(默认 - `false`):**
869
+ ```tsx
870
+ <MapView
871
+ myLocationEnabled={true}
872
+ followUserLocation={false} // 或省略
873
+ />
874
+ ```
875
+ - ✅ 显示定位点
876
+ - ✅ 用户可自由滑动地图
877
+ - ✅ 地图不会自动移动
878
+
879
+ **导航模式(`true`):**
880
+ ```tsx
881
+ <MapView
882
+ myLocationEnabled={true}
883
+ followUserLocation={true}
884
+ />
885
+ ```
886
+ - ✅ 显示定位点
887
+ - ✅ 地图自动跟随用户移动
888
+ - ⚠️ 适合导航场景
889
+
890
+ 详细说明请参考:[docs/followUserLocation.md](docs/followUserLocation.md)
891
+
892
+ ### 命令式 API 批量操作
893
+
894
+ ```tsx
895
+ const mapRef = useRef<MapViewRef>(null);
896
+
897
+ // 批量添加覆盖物
898
+ const addMultipleOverlays = async () => {
899
+ // 添加多个圆形
900
+ await mapRef.current?.addCircle('circle1', {
901
+ center: { latitude: 39.9, longitude: 116.4 },
902
+ radius: 1000,
903
+ fillColor: 0x8800FF00,
904
+ });
905
+
906
+ await mapRef.current?.addCircle('circle2', {
907
+ center: { latitude: 40.0, longitude: 116.5 },
908
+ radius: 500,
909
+ fillColor: 0x880000FF,
910
+ });
911
+
912
+ // 添加标记
913
+ await mapRef.current?.addMarker('marker1', {
914
+ position: { latitude: 39.95, longitude: 116.45 },
915
+ title: '北京',
916
+ });
917
+ };
918
+
919
+ // 批量清除
920
+ const clearAll = async () => {
921
+ await mapRef.current?.removeCircle('circle1');
922
+ await mapRef.current?.removeCircle('circle2');
923
+ await mapRef.current?.removeMarker('marker1');
924
+ };
925
+ ```
926
+
927
+ ## ⚠️ 注意事项
928
+
929
+ ### 权限配置
930
+
931
+ 在 `app.json` 中配置定位权限(Android):
932
+
933
+ ```json
934
+ {
935
+ "expo": {
936
+ "android": {
937
+ "permissions": [
938
+ "ACCESS_FINE_LOCATION",
939
+ "ACCESS_COARSE_LOCATION"
940
+ ]
941
+ }
942
+ }
943
+ }
944
+ ```
945
+
946
+ ### 颜色格式
947
+
948
+ 覆盖物颜色支持两种格式:
949
+
950
+ 1. **字符串格式**(ARGB):`"#AARRGGBB"`
951
+ ```tsx
952
+ <Circle fillColor="#8800FF00" /> // 50% 透明绿色
953
+ ```
954
+
955
+ 2. **数字格式**(命令式 API):`0xAARRGGBB`
956
+ ```tsx
957
+ await mapRef.current?.addCircle('circle1', {
958
+ fillColor: 0x8800FF00, // 50% 透明绿色
959
+ });
960
+ ```
961
+
962
+ ### 性能优化
963
+
964
+ - ✅ 使用命令式 API 处理大量覆盖物
965
+ - ✅ 及时移除不需要的覆盖物
966
+ - ✅ 避免在 `onPress` 等高频事件中进行复杂操作
967
+ - ✅ 定位间隔不要设置太小(建议 >= 1000ms)
968
+
969
+ ## 🤝 贡献
970
+
971
+ 欢迎提交 Issue 和 Pull Request!
972
+
973
+ ## 📄 许可证
974
+
975
+ MIT
976
+
977
+ ## 🔗 相关链接
978
+
979
+ - [高德地图开放平台](https://lbs.amap.com/)
980
+ - [高德地图 Android SDK](https://lbs.amap.com/api/android-sdk/summary)
981
+ - [Expo Modules API](https://docs.expo.dev/modules/overview/)
982
+ - [GitHub 仓库](https://github.com/yourusername/expo-gaode-map)
983
+
984
+ ## 📮 反馈与支持
985
+
986
+ 如果你在使用过程中遇到问题或有任何建议,欢迎:
987
+
988
+ - 📝 提交 [GitHub Issue](https://github.com/yourusername/expo-gaode-map/issues)
989
+ - 💬 参与 [Discussions](https://github.com/yourusername/expo-gaode-map/discussions)
990
+ - ⭐ 给项目点个 Star 支持一下