expo-gaode-map 2.0.0-alpha.6 → 2.0.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/docs/EXAMPLES.md DELETED
@@ -1,922 +0,0 @@
1
- # 使用示例
2
-
3
- [English](./EXAMPLES.en.md) | 简体中文
4
-
5
- 完整的使用示例和最佳实践。
6
-
7
- > 📖 **推荐阅读**: [初始化指南](./INITIALIZATION.md) - 详细的初始化流程和权限处理
8
-
9
- ## 目录
10
-
11
- - [完整应用示例](#完整应用示例)
12
- - [基础地图应用](#基础地图应用)
13
- - [定位追踪应用](#定位追踪应用)
14
- - [覆盖物示例](#覆盖物示例)
15
- - [高级用法](#高级用法)
16
-
17
- ## 完整应用示例
18
-
19
- 包含权限管理、错误处理和加载状态的完整示例:
20
-
21
- ```tsx
22
- import { useEffect, useState } from 'react';
23
- import { View, Text, Alert, Linking, Platform } from 'react-native';
24
- import {
25
- MapView,
26
- ExpoGaodeMapModule,
27
- type LatLng,
28
- } from 'expo-gaode-map';
29
-
30
- export default function App() {
31
- const [initialPosition, setInitialPosition] = useState<{
32
- target: LatLng;
33
- zoom: number;
34
- } | null>(null);
35
- const [error, setError] = useState<string | null>(null);
36
-
37
- useEffect(() => {
38
- const initialize = async () => {
39
- try {
40
- // 1. 初始化 SDK
41
- ExpoGaodeMapModule.initSDK({
42
- androidKey: 'your-android-api-key',
43
- iosKey: 'your-ios-api-key',
44
- });
45
-
46
- // 2. 检查权限
47
- const status = await ExpoGaodeMapModule.checkLocationPermission();
48
-
49
- // 3. 请求权限(如果需要)
50
- if (!status.granted) {
51
- const result = await ExpoGaodeMapModule.requestLocationPermission();
52
-
53
- if (!result.granted) {
54
- // 权限被拒绝
55
- setInitialPosition({
56
- target: { latitude: 39.9, longitude: 116.4 },
57
- zoom: 10
58
- });
59
-
60
- // 引导用户到设置
61
- Alert.alert(
62
- '需要定位权限',
63
- '请在设置中开启定位权限',
64
- [
65
- { text: '取消' },
66
- { text: '去设置', onPress: () => {
67
- if (Platform.OS === 'ios') {
68
- Linking.openURL('app-settings:');
69
- } else {
70
- Linking.openSettings();
71
- }
72
- }}
73
- ]
74
- );
75
- return;
76
- }
77
- }
78
-
79
- // 4. 获取位置
80
- const location = await ExpoGaodeMapModule.getCurrentLocation();
81
- setInitialPosition({
82
- target: {
83
- latitude: location.latitude,
84
- longitude: location.longitude
85
- },
86
- zoom: 15
87
- });
88
-
89
- } catch (err) {
90
- console.error('初始化失败:', err);
91
- setError('初始化失败');
92
- setInitialPosition({
93
- target: { latitude: 39.9, longitude: 116.4 },
94
- zoom: 10
95
- });
96
- }
97
- };
98
-
99
- initialize();
100
- }, []);
101
-
102
- // 加载状态
103
- if (!initialPosition && !error) {
104
- return (
105
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
106
- <Text>正在加载地图...</Text>
107
- </View>
108
- );
109
- }
110
-
111
- // 错误状态
112
- if (error) {
113
- return (
114
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
115
- <Text>{error}</Text>
116
- </View>
117
- );
118
- }
119
-
120
- return (
121
- <MapView
122
- style={{ flex: 1 }}
123
- initialCameraPosition={initialPosition!}
124
- myLocationEnabled={true}
125
- onLoad={() => console.log('地图加载完成')}
126
- />
127
- );
128
- }
129
- ```
130
-
131
- ## 基础地图应用
132
-
133
- ```tsx
134
- import React, { useRef, useEffect } from 'react';
135
- import { View, StyleSheet, Button } from 'react-native';
136
- import {
137
- MapView,
138
- ExpoGaodeMapModule,
139
- Circle,
140
- Marker,
141
- Polyline,
142
- Polygon,
143
- type MapViewRef
144
- } from 'expo-gaode-map';
145
-
146
- export default function App() {
147
- const mapRef = useRef<MapViewRef>(null);
148
-
149
- useEffect(() => {
150
- const initialize = async () => {
151
- ExpoGaodeMapModule.initSDK({
152
- androidKey: 'your-android-api-key',
153
- iosKey: 'your-ios-api-key',
154
- });
155
-
156
- // 检查并请求权限
157
- const status = await ExpoGaodeMapModule.checkLocationPermission();
158
- if (!status.granted) {
159
- await ExpoGaodeMapModule.requestLocationPermission();
160
- }
161
- };
162
-
163
- initialize();
164
- }, []);
165
-
166
- const handleMoveCamera = async () => {
167
- await mapRef.current?.moveCamera(
168
- {
169
- target: { latitude: 40.0, longitude: 116.5 },
170
- zoom: 15,
171
- },
172
- 1000
173
- );
174
- };
175
-
176
- return (
177
- <View style={styles.container}>
178
- <MapView
179
- ref={mapRef}
180
- style={styles.map}
181
- initialCameraPosition={{
182
- target: { latitude: 39.9, longitude: 116.4 },
183
- zoom: 10,
184
- }}
185
- myLocationEnabled={true}
186
- followUserLocation={false}
187
- trafficEnabled={true}
188
- onMapPress={(e) => console.log('点击地图', e.nativeEvent)}
189
- onLoad={() => console.log('地图加载完成')}
190
- >
191
- {/* 圆形覆盖物 */}
192
- <Circle
193
- center={{ latitude: 39.9, longitude: 116.4 }}
194
- radius={1000}
195
- fillColor="#8800FF00"
196
- strokeColor="#FFFF0000"
197
- strokeWidth={2}
198
- />
199
-
200
- {/* 标记点 */}
201
- <Marker
202
- position={{ latitude: 39.95, longitude: 116.45 }}
203
- title="这是一个标记"
204
- draggable={true}
205
- />
206
-
207
- {/* 折线 */}
208
- <Polyline
209
- points={[
210
- { latitude: 39.9, longitude: 116.4 },
211
- { latitude: 39.95, longitude: 116.45 },
212
- { latitude: 40.0, longitude: 116.5 },
213
- ]}
214
- strokeWidth={5}
215
- strokeColor="#FF0000FF"
216
- />
217
-
218
- {/* 多边形 */}
219
- <Polygon
220
- points={[
221
- { latitude: 39.85, longitude: 116.35 },
222
- { latitude: 39.85, longitude: 116.45 },
223
- { latitude: 39.75, longitude: 116.40 },
224
- ]}
225
- fillColor="#880000FF"
226
- strokeColor="#FFFF0000"
227
- strokeWidth={2}
228
- />
229
- </MapView>
230
-
231
- <View style={styles.controls}>
232
- <Button title="移动相机" onPress={handleMoveCamera} />
233
- </View>
234
- </View>
235
- );
236
- }
237
-
238
- const styles = StyleSheet.create({
239
- container: {
240
- flex: 1,
241
- },
242
- map: {
243
- flex: 1,
244
- },
245
- controls: {
246
- position: 'absolute',
247
- bottom: 20,
248
- left: 20,
249
- right: 20,
250
- },
251
- });
252
- ```
253
-
254
- ## 定位追踪应用
255
-
256
- ```tsx
257
- import React, { useEffect, useState } from 'react';
258
- import { View, Text, Button, StyleSheet } from 'react-native';
259
- import {
260
- MapView,
261
- ExpoGaodeMapModule,
262
- type Location,
263
- } from 'expo-gaode-map';
264
-
265
- export default function LocationApp() {
266
- const [location, setLocation] = useState<Location | null>(null);
267
- const [isTracking, setIsTracking] = useState(false);
268
-
269
- useEffect(() => {
270
- const initialize = async () => {
271
- // 初始化 SDK
272
- ExpoGaodeMapModule.initSDK({
273
- androidKey: 'your-android-api-key',
274
- iosKey: 'your-ios-api-key',
275
- });
276
-
277
- // 检查并请求权限
278
- const status = await ExpoGaodeMapModule.checkLocationPermission();
279
- if (!status.granted) {
280
- await ExpoGaodeMapModule.requestLocationPermission();
281
- }
282
-
283
- // 配置定位参数
284
- ExpoGaodeMapModule.setLocatingWithReGeocode(true);
285
- ExpoGaodeMapModule.setLocationMode(0);
286
- ExpoGaodeMapModule.setInterval(2000);
287
-
288
- // 监听位置更新
289
- const subscription = ExpoGaodeMapModule.addLocationListener('onLocationUpdate', (loc) => {
290
- console.log('位置更新:', loc);
291
- setLocation(loc);
292
- });
293
-
294
- return () => subscription.remove();
295
- };
296
-
297
- initialize();
298
- }, []);
299
-
300
- const handleStartTracking = () => {
301
- ExpoGaodeMapModule.start();
302
- setIsTracking(true);
303
- };
304
-
305
- const handleStopTracking = () => {
306
- ExpoGaodeMapModule.stop();
307
- setIsTracking(false);
308
- };
309
-
310
- const handleGetLocation = async () => {
311
- try {
312
- const loc = await ExpoGaodeMapModule.getCurrentLocation();
313
- setLocation(loc);
314
- } catch (error) {
315
- console.error('获取位置失败:', error);
316
- }
317
- };
318
-
319
- return (
320
- <View style={styles.container}>
321
- <MapView
322
- style={styles.map}
323
- myLocationEnabled={true}
324
- followUserLocation={isTracking}
325
- initialCameraPosition={{
326
- target: {
327
- latitude: location?.latitude || 39.9,
328
- longitude: location?.longitude || 116.4
329
- },
330
- zoom: 15,
331
- }}
332
- />
333
-
334
- {location && (
335
- <View style={styles.info}>
336
- <Text style={styles.infoText}>
337
- 纬度: {location.latitude.toFixed(6)}
338
- </Text>
339
- <Text style={styles.infoText}>
340
- 经度: {location.longitude.toFixed(6)}
341
- </Text>
342
- <Text style={styles.infoText}>
343
- 精度: {location.accuracy.toFixed(2)} 米
344
- </Text>
345
- {location.address && (
346
- <Text style={styles.infoText}>
347
- 地址: {location.address}
348
- </Text>
349
- )}
350
- </View>
351
- )}
352
-
353
- <View style={styles.controls}>
354
- <Button
355
- title="获取位置"
356
- onPress={handleGetLocation}
357
- />
358
- <View style={{ height: 10 }} />
359
- <Button
360
- title={isTracking ? '停止追踪' : '开始追踪'}
361
- onPress={isTracking ? handleStopTracking : handleStartTracking}
362
- color={isTracking ? '#FF3B30' : '#007AFF'}
363
- />
364
- </View>
365
- </View>
366
- );
367
- }
368
-
369
- const styles = StyleSheet.create({
370
- container: {
371
- flex: 1,
372
- },
373
- map: {
374
- flex: 1,
375
- },
376
- info: {
377
- position: 'absolute',
378
- top: 50,
379
- left: 20,
380
- right: 20,
381
- backgroundColor: 'white',
382
- padding: 15,
383
- borderRadius: 10,
384
- shadowColor: '#000',
385
- shadowOffset: { width: 0, height: 2 },
386
- shadowOpacity: 0.25,
387
- shadowRadius: 3.84,
388
- elevation: 5,
389
- },
390
- infoText: {
391
- fontSize: 14,
392
- marginBottom: 5,
393
- color: '#333',
394
- },
395
- controls: {
396
- position: 'absolute',
397
- bottom: 30,
398
- left: 20,
399
- right: 20,
400
- },
401
- });
402
- ```
403
-
404
- ## 覆盖物示例
405
-
406
- ### Circle (圆形)
407
-
408
- **声明式用法:**
409
- ```tsx
410
- <MapView style={{ flex: 1 }}>
411
- <Circle
412
- center={{ latitude: 39.9, longitude: 116.4 }}
413
- radius={1000}
414
- fillColor="#8800FF00"
415
- strokeColor="#FFFF0000"
416
- strokeWidth={2}
417
- onPress={(e) => console.log('点击圆形')}
418
- />
419
- </MapView>
420
- ```
421
-
422
-
423
- ### Marker (标记点)
424
-
425
- #### 基础用法
426
-
427
- **声明式用法:**
428
- ```tsx
429
- <MapView style={{ flex: 1 }}>
430
- <Marker
431
- position={{ latitude: 39.9, longitude: 116.4 }}
432
- title="标题"
433
- snippet="描述信息"
434
- draggable={true}
435
- onPress={(e) => console.log('点击标记')}
436
- onDragEnd={(e) => console.log('拖动结束', e.nativeEvent)}
437
- />
438
- </MapView>
439
- ```
440
-
441
- **命令式用法:**
442
- ```tsx
443
- await mapRef.current?.addMarker('marker1', {
444
- position: { latitude: 39.9, longitude: 116.4 },
445
- title: '标题',
446
- snippet: '描述信息',
447
- draggable: true,
448
- });
449
-
450
- await mapRef.current?.updateMarker('marker1', {
451
- position: { latitude: 40.0, longitude: 116.5 },
452
- });
453
-
454
- await mapRef.current?.removeMarker('marker1');
455
- ```
456
-
457
- > **⚠️ 限制**:命令式 API 添加的 Marker **不支持事件回调**(onPress, onDragEnd 等)和**自定义视图**。如需这些功能,请使用声明式 `<Marker>` 组件。
458
-
459
- #### 自定义图标
460
-
461
- ```tsx
462
- import { Image } from 'react-native';
463
-
464
- // 获取本地图片 URI
465
- const iconUri = Image.resolveAssetSource(require('./assets/marker-icon.png')).uri;
466
-
467
- <MapView style={{ flex: 1 }}>
468
- <Marker
469
- position={{ latitude: 39.9, longitude: 116.4 }}
470
- title="自定义图标"
471
- icon={iconUri}
472
- iconWidth={50}
473
- iconHeight={50}
474
- onPress={(e) => console.log('点击自定义图标标记')}
475
- />
476
- </MapView>
477
- ```
478
-
479
- > **注意**:
480
- > - `iconWidth` 和 `iconHeight` 使用点(points)作为单位
481
- > - 在不同密度屏幕上会自动缩放,保持视觉一致性
482
- > - 支持网络图片(http/https)和本地图片
483
-
484
- #### 自定义视图 ⭐ 推荐
485
-
486
- 使用 `children` 属性可以完全自定义标记的外观,支持任意 React Native 组件和样式:
487
-
488
- **基础自定义视图:**
489
- ```tsx
490
- import { View, Text, StyleSheet } from 'react-native';
491
-
492
- <MapView style={{ flex: 1 }}>
493
- <Marker
494
- position={{ latitude: 39.9, longitude: 116.4 }}
495
- customViewWidth={200}
496
- customViewHeight={50}
497
- onPress={(e) => Alert.alert('标记', '点击了自定义标记')}
498
- >
499
- <View style={styles.markerContainer}>
500
- <Text style={styles.markerText}>北京市中心</Text>
501
- </View>
502
- </Marker>
503
- </MapView>
504
-
505
- const styles = StyleSheet.create({
506
- markerContainer: {
507
- backgroundColor: '#fff',
508
- borderColor: '#2196F3',
509
- borderWidth: 2,
510
- borderRadius: 12,
511
- paddingVertical: 8,
512
- paddingHorizontal: 16,
513
- shadowColor: '#000',
514
- shadowOffset: { width: 0, height: 2 },
515
- shadowOpacity: 0.25,
516
- shadowRadius: 3.84,
517
- elevation: 5,
518
- },
519
- markerText: {
520
- color: '#2196F3',
521
- fontSize: 14,
522
- fontWeight: 'bold',
523
- },
524
- });
525
- ```
526
-
527
- **带图标的自定义视图:**
528
- ```tsx
529
- import { View, Text, Image, StyleSheet } from 'react-native';
530
-
531
- <MapView style={{ flex: 1 }}>
532
- <Marker
533
- position={{ latitude: 39.9, longitude: 116.4 }}
534
- iconWidth={150}
535
- iconHeight={60}
536
- >
537
- <View style={styles.customMarker}>
538
- <Image
539
- source={require('./assets/location-pin.png')}
540
- style={styles.markerIcon}
541
- />
542
- <View style={styles.markerContent}>
543
- <Text style={styles.markerTitle}>北京</Text>
544
- <Text style={styles.markerSubtitle}>中国首都</Text>
545
- </View>
546
- </View>
547
- </Marker>
548
- </MapView>
549
-
550
- const styles = StyleSheet.create({
551
- customMarker: {
552
- flexDirection: 'row',
553
- alignItems: 'center',
554
- backgroundColor: '#4CAF50',
555
- borderRadius: 20,
556
- paddingVertical: 6,
557
- paddingHorizontal: 12,
558
- shadowColor: '#000',
559
- shadowOffset: { width: 0, height: 2 },
560
- shadowOpacity: 0.3,
561
- shadowRadius: 4,
562
- elevation: 6,
563
- },
564
- markerIcon: {
565
- width: 24,
566
- height: 24,
567
- marginRight: 8,
568
- },
569
- markerContent: {
570
- flexDirection: 'column',
571
- },
572
- markerTitle: {
573
- color: '#fff',
574
- fontSize: 14,
575
- fontWeight: 'bold',
576
- },
577
- markerSubtitle: {
578
- color: '#E8F5E9',
579
- fontSize: 11,
580
- },
581
- });
582
- ```
583
-
584
- **动态内容标记:**
585
- ```tsx
586
- import { View, Text, StyleSheet } from 'react-native';
587
-
588
- function LocationMarker({ location }: { location: Location }) {
589
- return (
590
- <Marker
591
- position={{
592
- latitude: location.latitude,
593
- longitude: location.longitude
594
- }}
595
- customViewWidth={220}
596
- customViewHeight={60}
597
- onPress={(e) => Alert.alert('位置', location.address)}
598
- >
599
- <View style={styles.locationMarker}>
600
- <Text style={styles.locationTitle} numberOfLines={1}>
601
- {location.address || '当前位置'}
602
- </Text>
603
- <Text style={styles.locationCoords}>
604
- {location.latitude.toFixed(6)}, {location.longitude.toFixed(6)}
605
- </Text>
606
- </View>
607
- </Marker>
608
- );
609
- }
610
-
611
- const styles = StyleSheet.create({
612
- locationMarker: {
613
- backgroundColor: '#FF5722',
614
- borderRadius: 10,
615
- paddingVertical: 8,
616
- paddingHorizontal: 12,
617
- borderLeftWidth: 4,
618
- borderLeftColor: '#D84315',
619
- shadowColor: '#000',
620
- shadowOffset: { width: 0, height: 2 },
621
- shadowOpacity: 0.25,
622
- shadowRadius: 3.84,
623
- elevation: 5,
624
- },
625
- locationTitle: {
626
- color: '#fff',
627
- fontSize: 13,
628
- fontWeight: '600',
629
- marginBottom: 2,
630
- },
631
- locationCoords: {
632
- color: '#FFCCBC',
633
- fontSize: 10,
634
- },
635
- });
636
- ```
637
-
638
- **价格标签样式:**
639
- ```tsx
640
- <Marker
641
- position={{ latitude: 39.9, longitude: 116.4 }}
642
- iconWidth={80}
643
- iconHeight={40}
644
- >
645
- <View style={styles.priceTag}>
646
- <Text style={styles.priceText}>¥1280</Text>
647
- <View style={styles.priceArrow} />
648
- </View>
649
- </Marker>
650
-
651
- const styles = StyleSheet.create({
652
- priceTag: {
653
- backgroundColor: '#FF9800',
654
- borderRadius: 8,
655
- paddingVertical: 6,
656
- paddingHorizontal: 12,
657
- position: 'relative',
658
- },
659
- priceText: {
660
- color: '#fff',
661
- fontSize: 16,
662
- fontWeight: 'bold',
663
- },
664
- priceArrow: {
665
- position: 'absolute',
666
- bottom: -6,
667
- left: '50%',
668
- marginLeft: -6,
669
- width: 0,
670
- height: 0,
671
- borderLeftWidth: 6,
672
- borderRightWidth: 6,
673
- borderTopWidth: 6,
674
- borderStyle: 'solid',
675
- borderLeftColor: 'transparent',
676
- borderRightColor: 'transparent',
677
- borderTopColor: '#FF9800',
678
- },
679
- });
680
- ```
681
-
682
- > **自定义视图要点**:
683
- > - ✅ 支持所有 React Native 样式(backgroundColor、borderRadius、flexbox、shadow 等)
684
- > - ✅ 使用 `iconWidth` 和 `iconHeight` 控制最终显示尺寸
685
- > - ✅ 子视图会自动转换为图片显示在地图上
686
- > - ✅ 支持动态内容和复杂布局
687
- > - ⚠️ 仅支持声明式 `<Marker>` 组件
688
- > - ⚠️ 建议明确指定 `iconWidth` 和 `iconHeight` 以确保跨设备一致性
689
- > - ⚠️ iOS 的 shadow 样式可能需要额外配置(shadowColor、shadowOffset 等)
690
-
691
- #### Android 特有属性
692
-
693
- ```tsx
694
- <MapView style={{ flex: 1 }}>
695
- <Marker
696
- position={{ latitude: 39.9, longitude: 116.4 }}
697
- title="Android 特性"
698
- opacity={0.8}
699
- flat={true}
700
- zIndex={10}
701
- anchor={{ x: 0.5, y: 1.0 }}
702
- />
703
- </MapView>
704
- ```
705
-
706
- #### iOS 特有属性
707
-
708
- ```tsx
709
- import { Platform } from 'react-native';
710
-
711
- <MapView style={{ flex: 1 }}>
712
- {Platform.OS === 'ios' && (
713
- <Marker
714
- position={{ latitude: 39.9, longitude: 116.4 }}
715
- title="iOS 特性"
716
- pinColor="green"
717
- animatesDrop={true}
718
- centerOffset={{ x: 0, y: -20 }}
719
- />
720
- )}
721
- </MapView>
722
- ```
723
-
724
- #### 拖拽事件处理
725
-
726
- > **注意**:事件处理仅在声明式 `<Marker>` 组件中有效
727
-
728
- ```tsx
729
- <MapView style={{ flex: 1 }}>
730
- <Marker
731
- position={{ latitude: 39.9, longitude: 116.4 }}
732
- title="可拖拽标记"
733
- draggable={true}
734
- onDragStart={(e) => console.log('开始拖拽', e.nativeEvent)}
735
- onDrag={(e) => console.log('拖拽中', e.nativeEvent)}
736
- onDragEnd={(e) => {
737
- const { latitude, longitude } = e.nativeEvent;
738
- console.log(`拖拽结束: ${latitude}, ${longitude}`);
739
- Alert.alert('新位置', `纬度: ${latitude.toFixed(6)}\n经度: ${longitude.toFixed(6)}`);
740
- }}
741
- />
742
- </MapView>
743
- ```
744
-
745
- ### Polyline (折线)
746
-
747
- **声明式用法 - 普通折线:**
748
- ```tsx
749
- <MapView style={{ flex: 1 }}>
750
- <Polyline
751
- points={[
752
- { latitude: 39.9, longitude: 116.4 },
753
- { latitude: 39.95, longitude: 116.45 },
754
- { latitude: 40.0, longitude: 116.5 },
755
- ]}
756
- width={5}
757
- color="#FFFF0000"
758
- onPress={(e) => console.log('点击折线')}
759
- />
760
- </MapView>
761
- ```
762
-
763
- **声明式用法 - 纹理折线:**
764
- ```tsx
765
- import { Image } from 'react-native';
766
-
767
- const iconUri = Image.resolveAssetSource(require('./assets/arrow.png')).uri;
768
-
769
- <MapView style={{ flex: 1 }}>
770
- <Polyline
771
- points={[
772
- { latitude: 39.9, longitude: 116.4 },
773
- { latitude: 39.95, longitude: 116.45 },
774
- { latitude: 40.0, longitude: 116.5 },
775
- ]}
776
- width={20}
777
- color="#FFFF0000"
778
- texture={iconUri}
779
- onPress={(e) => console.log('点击纹理折线')}
780
- />
781
- </MapView>
782
- ```
783
-
784
- **命令式用法:**
785
- ```tsx
786
- // 普通折线
787
- await mapRef.current?.addPolyline('polyline1', {
788
- points: [
789
- { latitude: 39.9, longitude: 116.4 },
790
- { latitude: 40.0, longitude: 116.5 },
791
- ],
792
- width: 5,
793
- color: '#FFFF0000',
794
- });
795
-
796
- // 纹理折线
797
- await mapRef.current?.addPolyline('polyline2', {
798
- points: [
799
- { latitude: 39.9, longitude: 116.4 },
800
- { latitude: 40.0, longitude: 116.5 },
801
- ],
802
- width: 20,
803
- color: '#FFFF0000',
804
- texture: iconUri,
805
- });
806
-
807
- // 分段纹理示例(使用多个 Polyline)
808
- const point1 = { latitude: 39.9, longitude: 116.4 };
809
- const point2 = { latitude: 39.95, longitude: 116.45 };
810
- const point3 = { latitude: 40.0, longitude: 116.5 };
811
-
812
- // 第一段:红色箭头
813
- await mapRef.current?.addPolyline('segment1', {
814
- points: [point1, point2],
815
- width: 20,
816
- color: '#FFFF0000',
817
- texture: redArrowUri,
818
- });
819
-
820
- // 第二段:蓝色箭头
821
- await mapRef.current?.addPolyline('segment2', {
822
- points: [point2, point3],
823
- width: 20,
824
- color: '#FF0000FF',
825
- texture: blueArrowUri,
826
- });
827
- ```
828
-
829
- > **注意**:
830
- > - 颜色格式使用 ARGB(`#AARRGGBB`),例如 `#FFFF0000` 表示不透明红色
831
- > - `texture` 支持网络图片(http/https)和本地文件(file://)
832
- > - 纹理图片会沿着折线方向平铺显示
833
- > - 建议纹理折线使用较大的 `width` 值(如 20)以获得更好的显示效果
834
- > - **分段纹理限制**:单个 Polyline 只能设置一个纹理。如需不同线段使用不同纹理,请创建多个 Polyline 组件
835
-
836
- ### Polygon (多边形)
837
-
838
- **声明式用法:**
839
- ```tsx
840
- <MapView style={{ flex: 1 }}>
841
- <Polygon
842
- points={[
843
- { latitude: 39.9, longitude: 116.3 },
844
- { latitude: 39.9, longitude: 116.4 },
845
- { latitude: 39.8, longitude: 116.4 },
846
- ]}
847
- fillColor="#8800FF00"
848
- strokeColor="#FFFF0000"
849
- strokeWidth={2}
850
- onPress={(e) => console.log('点击多边形')}
851
- />
852
- </MapView>
853
- ```
854
-
855
- **命令式用法:**
856
- ```tsx
857
- await mapRef.current?.addPolygon('polygon1', {
858
- points: [
859
- { latitude: 39.9, longitude: 116.3 },
860
- { latitude: 39.9, longitude: 116.4 },
861
- { latitude: 39.8, longitude: 116.4 },
862
- ],
863
- fillColor: 0x8800FF00,
864
- strokeColor: 0xFFFF0000,
865
- strokeWidth: 2,
866
- });
867
- ```
868
-
869
- ## 高级用法
870
-
871
- ### 自定义定位蓝点
872
-
873
- ```tsx
874
- import { Image } from 'react-native';
875
-
876
- const iconUri = Image.resolveAssetSource(require('./assets/location-icon.png')).uri;
877
-
878
- <MapView
879
- myLocationEnabled={true}
880
- userLocationRepresentation={{
881
- showsAccuracyRing: true,
882
- fillColor: '#4285F4',
883
- strokeColor: '#1967D2',
884
- lineWidth: 2,
885
- image: iconUri,
886
- imageWidth: 40,
887
- imageHeight: 40,
888
- }}
889
- />
890
- ```
891
-
892
- ### 缩放级别限制
893
-
894
- ```tsx
895
- <MapView
896
- maxZoom={18}
897
- minZoom={5}
898
- initialCameraPosition={{
899
- target: { latitude: 39.9, longitude: 116.4 },
900
- zoom: 10,
901
- }}
902
- />
903
- ```
904
-
905
- ### 方向更新 (iOS)
906
-
907
- ```tsx
908
- import { ExpoGaodeMapModule } from 'expo-gaode-map';
909
-
910
- // 开始方向更新
911
- ExpoGaodeMapModule.startUpdatingHeading();
912
-
913
- // 停止方向更新
914
- ExpoGaodeMapModule.stopUpdatingHeading();
915
-
916
- // 监听方向更新
917
- const subscription = ExpoGaodeMapModule.onHeadingUpdate('onHeadingUpdate', (heading) => {
918
- console.log('方向更新:', heading);
919
- });
920
-
921
- // 取消监听
922
- subscription.remove();