Android开发求助:基于PlaceAutocompleteFragment输入绘制地图路径
嗨,我来帮你搞定这个问题!其实从PlaceAutocompleteFragment获取地点后绘制路径,核心逻辑和点击地图选点的方式是相通的,只是获取起点终点坐标的入口不同而已。下面我给你一步步拆解实现过程:
第一步:从PlaceAutocompleteFragment获取起点/终点的经纬度
首先你需要处理PlaceAutocomplete的返回结果,拿到选中地点的LatLng坐标,把起点和终点分别存起来。这里是示例代码:
private static final int REQUEST_ORIGIN = 1; private static final int REQUEST_DESTINATION = 2; private LatLng mOriginLatLng; private LatLng mDestinationLatLng; private GoogleMap mMap; // 启动起点选择的自动完成框 public void launchOriginAutocomplete() { try { Intent intent = new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN) .build(this); startActivityForResult(intent, REQUEST_ORIGIN); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "无法启动地点选择", Toast.LENGTH_SHORT).show(); } } // 启动终点选择的自动完成框 public void launchDestinationAutocomplete() { try { Intent intent = new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN) .build(this); startActivityForResult(intent, REQUEST_DESTINATION); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "无法启动地点选择", Toast.LENGTH_SHORT).show(); } } // 处理自动完成框的返回结果 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && data != null) { Place selectedPlace = PlaceAutocomplete.getPlace(this, data); if (requestCode == REQUEST_ORIGIN) { mOriginLatLng = selectedPlace.getLatLng(); // 给起点加个标记 mMap.addMarker(new MarkerOptions().position(mOriginLatLng).title("起点")); } else if (requestCode == REQUEST_DESTINATION) { mDestinationLatLng = selectedPlace.getLatLng(); mMap.addMarker(new MarkerOptions().position(mDestinationLatLng).title("终点")); // 当起点和终点都拿到后,就可以请求路径了 if (mOriginLatLng != null) { fetchRouteData(); } else { Toast.makeText(this, "请先选择起点", Toast.LENGTH_SHORT).show(); } } } }
第二步:调用Google Directions API获取路径数据
要绘制路径,你需要先从Google Directions API拿到路径的坐标点集合。这里我用OkHttp来发送网络请求,你需要先在build.gradle里添加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
然后写请求路径的方法,以及解析返回的JSON数据,解码Polyline字符串(API返回的路径点是编码后的字符串):
private void fetchRouteData() { String apiKey = "你的Google Maps API Key"; // 替换成你自己的API Key String requestUrl = String.format( "https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&key=%s", mOriginLatLng.latitude, mOriginLatLng.longitude, mDestinationLatLng.latitude, mDestinationLatLng.longitude, apiKey ); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(requestUrl).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(MainActivity.this, "获取路径失败,请检查网络", Toast.LENGTH_SHORT).show()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if (!response.isSuccessful()) { runOnUiThread(() -> Toast.makeText(MainActivity.this, "请求路径失败", Toast.LENGTH_SHORT).show()); return; } String jsonResponse = response.body().string(); try { JSONObject jsonObject = new JSONObject(jsonResponse); JSONArray routes = jsonObject.getJSONArray("routes"); if (routes.length() == 0) { runOnUiThread(() -> Toast.makeText(MainActivity.this, "未找到可行路径", Toast.LENGTH_SHORT).show()); return; } // 解析路径的Polyline点 JSONObject route = routes.getJSONObject(0); JSONArray legs = route.getJSONArray("legs"); JSONObject leg = legs.getJSONObject(0); JSONArray steps = leg.getJSONArray("steps"); List<LatLng> pathPoints = new ArrayList<>(); for (int i = 0; i < steps.length(); i++) { JSONObject step = steps.getJSONObject(i); JSONObject polyline = step.getJSONObject("polyline"); String encodedPoints = polyline.getString("points"); pathPoints.addAll(decodePolyline(encodedPoints)); } // 在UI线程绘制路径 runOnUiThread(() -> drawRouteOnMap(pathPoints)); } catch (JSONException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(MainActivity.this, "解析路径数据失败", Toast.LENGTH_SHORT).show()); } } }); } // 解码Polyline编码字符串的工具方法 private List<LatLng> decodePolyline(String encoded) { List<LatLng> polylinePoints = new ArrayList<>(); int index = 0; int lat = 0, lng = 0; int length = encoded.length(); while (index < length) { int shift = 0; int result = 0; int b; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1F) << shift; shift += 5; } while (b >= 0x20); int deltaLat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lat += deltaLat; shift = 0; result = 0; do { b = encoded.charAt(index++) - 63; result |= (b & 0x1F) << shift; shift += 5; } while (b >= 0x20); int deltaLng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); lng += deltaLng; polylinePoints.add(new LatLng((double) lat / 1E5, (double) lng / 1E5)); } return polylinePoints; }
第三步:在GoogleMap上绘制路径
拿到解码后的坐标点集合后,就可以用PolylineOptions在地图上画出路径了,还可以调整地图视角让起点终点都显示:
private void drawRouteOnMap(List<LatLng> pathPoints) { PolylineOptions polylineOptions = new PolylineOptions() .addAll(pathPoints) .width(12) // 设置路径宽度 .color(Color.parseColor("#1E88E5")) // 设置路径颜色 .geodesic(true); // 让路径沿着地球曲率绘制 // 添加路径到地图 mMap.addPolyline(polylineOptions); // 调整地图视角,包含起点和终点 LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder(); boundsBuilder.include(mOriginLatLng); boundsBuilder.include(mDestinationLatLng); LatLngBounds bounds = boundsBuilder.build(); // 移动相机到合适的位置,100是屏幕边距(像素) mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100)); }
重要注意事项
- 确保你在Google Cloud Console已经启用了Directions API,并且你的API Key配置了正确的权限和限制(比如绑定你的应用包名和SHA-1,防止被滥用)
- 别忘了在
AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
- 可以添加一些异常处理,比如用户未选择起点就选终点的情况,或者API请求返回空路径的情况
内容的提问来源于stack exchange,提问作者Ebet
相关产品推荐
相关产品推荐

