如何在react-native-maps中绘制两个位置间的路径?
在react-native-maps中绘制两点间路径的解决方案
方法一:绘制直线路径(简单快速)
react-native-maps自带的Polyline组件可以直接在两个坐标点间绘制直线,适合不需要真实道路导航的场景。
实现步骤:
- 导入Polyline组件
修改你的导入语句,添加Polyline:
import MapView, {Marker, Polyline} from 'react-native-maps';
- 在MapView中添加路径
在现有Marker组件后插入Polyline,传入包含当前位置和目标位置的坐标数组:
<MapView style={styles.map} region={mapRegion}> <Marker coordinate={mapRegionNow} title='MarkerNow'/> <Marker coordinate={mapRegion} title='Marker'/> {/* 两点间直线路径 */} <Polyline coordinates={[ {latitude: mapRegionNow.latitude, longitude: mapRegionNow.longitude}, {latitude: mapRegion.latitude, longitude: mapRegion.longitude} ]} strokeWidth={3} // 路径宽度 strokeColor="#007AFF" // 路径颜色,可自定义 /> </MapView>
- 优化地图视野(可选)
默认的mapRegion可能只显示目标位置,添加以下代码让两个点都处于地图视野内:
// 计算包含两个点的地图区域 const calculateMapRegion = (coords1, coords2) => { const minLat = Math.min(coords1.latitude, coords2.latitude); const maxLat = Math.max(coords1.latitude, coords2.latitude); const minLng = Math.min(coords1.longitude, coords2.longitude); const maxLng = Math.max(coords1.longitude, coords2.longitude); return { latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2, latitudeDelta: (maxLat - minLat) * 1.2, // 放大一点留边距 longitudeDelta: (maxLng - minLng) * 1.2, }; }; // 当两个位置都获取到后更新地图区域 useEffect(() => { if (mapRegionNow.latitude !== 1.3483 && mapRegion.latitude !== 1.3483) { setMapRegion(calculateMapRegion(mapRegionNow, mapRegion)); } }, [mapRegionNow, mapRegion]);
方法二:绘制真实导航路径(贴合实际道路)
如果需要基于真实道路的导航路径,需要调用第三方地图API(如高德、谷歌)获取路线规划数据,再用Polyline绘制。
实现步骤:
- 调用路线规划API
以高德地图为例,构造请求获取驾车/步行路线:
const [navigationPath, setNavigationPath] = useState([]); const fetchNavigationPath = async () => { const origin = `${mapRegionNow.longitude},${mapRegionNow.latitude}`; const destination = `${mapRegion.longitude},${mapRegion.latitude}`; const apiKey = '你的高德API密钥'; // 需前往高德开发者平台申请 try { const response = await fetch( `https://restapi.amap.com/v3/direction/driving?origin=${origin}&destination=${destination}&key=${apiKey}` ); const data = await response.json(); if (data.status === '1') { // 解析API返回的路径点 const path = data.route.paths[0].steps.flatMap(step => step.polyline.split(';').map(point => { const [lng, lat] = point.split(','); return {latitude: parseFloat(lat), longitude: parseFloat(lng)}; }) ); setNavigationPath(path); } } catch (error) { console.error('获取路径失败:', error); } };
- 绘制真实路径
在MapView中添加基于API数据的Polyline:
{navigationPath.length > 0 && ( <Polyline coordinates={navigationPath} strokeWidth={3} strokeColor="#007AFF" /> )}
完整修改后的代码示例
import { StyleSheet, Text, View, Dimensions, Button } from 'react-native' import React , {useEffect, useState} from 'react' import {ref, onValue} from 'firebase/database' import {db} from '../firebase' import MapView, {Marker, Polyline} from 'react-native-maps'; import * as Loc from 'expo-location'; const Location = ({route}) => { const paramKey = route.params.paramKey1 console.log(paramKey) var lo, ke; const [todoDatak, setToDoDatak] = useState([]) const [todoDatal, setToDoDatal] = useState([]) const [mapRegion, setMapRegion] = useState({ latitude: 1.3483, longitude: 103.6831, latitudeDelta: 0.005, longitudeDelta:0.0005, }) const [mapRegionNow, setMapRegionNow] = useState({ latitude: 1.3483, longitude: 103.6831, latitudeDelta: 0.005, longitudeDelta:0.0005, }) const [navigationPath, setNavigationPath] = useState([]); const userLocation = async()=>{ let { status } = await Loc.requestForegroundPermissionsAsync(); if (status !== 'granted') { alert('获取位置权限失败'); return; } let location = await Loc.getCurrentPositionAsync({enableHighAccuracy:true}); setMapRegionNow({ latitude:location.coords.latitude, longitude:location.coords.longitude, latitudeDelta:0.005, longitudeDelta:0.0005, }); console.log(location.coords.latitude, location.coords.longitude) } // 计算包含两个点的地图区域 const calculateMapRegion = (coords1, coords2) => { const minLat = Math.min(coords1.latitude, coords2.latitude); const maxLat = Math.max(coords1.latitude, coords2.latitude); const minLng = Math.min(coords1.longitude, coords2.longitude); const maxLng = Math.max(coords1.longitude, coords2.longitude); return { latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2, latitudeDelta: (maxLat - minLat) * 1.2, longitudeDelta: (maxLng - minLng) * 1.2, }; }; // 获取真实导航路径(以高德为例) const fetchNavigationPath = async () => { const origin = `${mapRegionNow.longitude},${mapRegionNow.latitude}`; const destination = `${mapRegion.longitude},${mapRegion.latitude}`; const apiKey = '你的高德API密钥'; // 替换为你的密钥 try { const response = await fetch( `https://restapi.amap.com/v3/direction/driving?origin=${origin}&destination=${destination}&key=${apiKey}` ); const data = await response.json(); if (data.status === '1') { const path = data.route.paths[0].steps.flatMap(step => step.polyline.split(';').map(point => { const [lng, lat] = point.split(','); return {latitude: parseFloat(lat), longitude: parseFloat(lng)}; }) ); setNavigationPath(path); } } catch (error) { console.error('获取路径失败:', error); } }; useEffect (() => { const starCountRef = ref(db, "food/" + paramKey); onValue(starCountRef, (snapshot) =>{ ke = snapshot.key; setToDoDatak(ke) // 注意:这里需要补充从firebase获取目标位置经纬度的逻辑 // 示例:const data = snapshot.val(); // setMapRegion({ // latitude: data.latitude, // longitude: data.longitude, // latitudeDelta: 0.005, // longitudeDelta:0.0005, // }); setToDoDatal(lo) }); userLocation(); }, []) // 更新地图区域和获取路径 useEffect(() => { if (mapRegionNow.latitude !== 1.3483 && mapRegion.latitude !== 1.3483) { setMapRegion(calculateMapRegion(mapRegionNow, mapRegion)); // fetchNavigationPath(); // 需要真实路径时取消注释 } }, [mapRegionNow, mapRegion]) return ( <View style = {styles.container}> <Text style = {styles.header}>Shop Name</Text> <Text style = {styles.text}>{todoDatak}</Text> <View style={styles.container}> <MapView style={styles.map} region={mapRegion}> <Marker coordinate={mapRegionNow} title='MarkerNow'/> <Marker coordinate={mapRegion} title='Marker'/> {/* 直线路径 */} <Polyline coordinates={[ {latitude: mapRegionNow.latitude, longitude: mapRegionNow.longitude}, {latitude: mapRegion.latitude, longitude: mapRegion.longitude} ]} strokeWidth={3} strokeColor="#007AFF" /> {/* 真实导航路径,启用时取消注释 */} {/* {navigationPath.length > 0 && ( <Polyline coordinates={navigationPath} strokeWidth={3} strokeColor="#007AFF" /> )} */} </MapView> <Button title= 'Get Location' onPress={userLocation}/> </View> </View> ) } export default Location const styles = StyleSheet.create({ container: { flex: 1, }, header: { fontSize: 20, fontWeight: 'bold', margin: 10, }, text: { fontSize: 16, marginHorizontal: 10, marginBottom: 10, }, map: { width: Dimensions.get('window').width, height: Dimensions.get('window').height * 0.7, }, })
提示:代码中
firebase部分需要补充目标位置经纬度的获取逻辑,否则目标位置会一直是默认值。若使用真实导航路径,需替换为自己的地图API密钥。
内容的提问来源于stack exchange,提问作者L.Calvin
相关产品推荐
相关产品推荐

