如何在Google Maps V2 Android上绘制交互式折线路线

54

我有以下代码,可以为我绘制折线,而且运行正常。但问题是它没有绘制交互式折线,绘制的线条缺少一些像素!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class testRoute extends FragmentActivity implements OnClickListener {

    private GoogleMap myMap;
    Polyline line;
    Context context;

    // Static LatLng
    LatLng startLatLng = new LatLng(30.707104, 76.690749);
    LatLng endLatLng = new LatLng(30.721419, 76.730017);

    public void onCreate(Bundle bd) {
        super.onCreate(bd);
        setContentView(R.layout.passanger_home_call);
        context = testRoute.this;

        // Temp GetTrails Button
        Button btntemp = (Button) findViewById(R.id.btn_pass_home_call_temp);
        btntemp.setOnClickListener(this);

        // GoogleMap myMap
        myMap = ((SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map_pass_home_call)).getMap();
        myMap.setMyLocationEnabled(true);
        myMap.moveCamera(CameraUpdateFactory.newLatLng(startLatLng));
        myMap.animateCamera(CameraUpdateFactory.zoomTo(12));

        // Now auto clicking the button
        btntemp.performClick();
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.btn_pass_home_call_temp:
            String urlTopass = makeURL(startLatLng.latitude,
                    startLatLng.longitude, endLatLng.latitude,
                    endLatLng.longitude);
            new connectAsyncTask(urlTopass).execute();
            break;

        default:
            break;
        }

    }

    private class connectAsyncTask extends AsyncTask<Void, Void, String> {
        private ProgressDialog progressDialog;
        String url;

        connectAsyncTask(String urlPass) {
            url = urlPass;
        }

        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            progressDialog = new ProgressDialog(context);
            progressDialog.setMessage("Fetching route, Please wait...");
            progressDialog.setIndeterminate(true);
            progressDialog.show();
        }

        @Override
        protected String doInBackground(Void... params) {
            JSONParser jParser = new JSONParser();
            String json = jParser.getJSONFromUrl(url);
            return json;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            progressDialog.hide();
            if (result != null) {
                drawPath(result);
            }
        }
    }

    public String makeURL(double sourcelat, double sourcelog, double destlat,
            double destlog) {
        StringBuilder urlString = new StringBuilder();
        urlString.append("http://maps.googleapis.com/maps/api/directions/json");
        urlString.append("?origin=");// from
        urlString.append(Double.toString(sourcelat));
        urlString.append(",");
        urlString.append(Double.toString(sourcelog));
        urlString.append("&destination=");// to
        urlString.append(Double.toString(destlat));
        urlString.append(",");
        urlString.append(Double.toString(destlog));
        urlString.append("&sensor=false&mode=driving&alternatives=true");
        return urlString.toString();
    }

    public class JSONParser {

        InputStream is = null;
        JSONObject jObj = null;
        String json = "";

        // constructor
        public JSONParser() {
        }

        public String getJSONFromUrl(String url) {

            // Making HTTP request
            try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(url);

                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(is, "iso-8859-1"), 8);
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }

                json = sb.toString();
                is.close();
            } catch (Exception e) {
                Log.e("Buffer Error", "Error converting result " + e.toString());
            }
            return json;

        }
    }

    public void drawPath(String result) {
        if (line != null) {
            myMap.clear();
        }
        myMap.addMarker(new MarkerOptions().position(endLatLng).icon(
                BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
        myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
                BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
        try {
            // Tranform the string into a json object
            final JSONObject json = new JSONObject(result);
            JSONArray routeArray = json.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);
            JSONObject overviewPolylines = routes
                    .getJSONObject("overview_polyline");
            String encodedString = overviewPolylines.getString("points");
            List<LatLng> list = decodePoly(encodedString);

            for (int z = 0; z < list.size() - 1; z++) {
                LatLng src = list.get(z);
                LatLng dest = list.get(z + 1);
                line = myMap.addPolyline(new PolylineOptions()
                        .add(new LatLng(src.latitude, src.longitude),
                                new LatLng(dest.latitude, dest.longitude))
                        .width(5).color(Color.BLUE).geodesic(true));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<LatLng>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }

        return poly;
    }
}

代码可以正常工作并绘制从一个地方到另一个地方的路径,但无法绘制交互式路径

截图:- enter image description here

我认为问题出在我的drawPath()方法中:

public void drawPath(String result) {
        if (line != null) {
            myMap.clear();
        }
        myMap.addMarker(new MarkerOptions().position(endLatLng).icon(
                BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
        myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
                BitmapDescriptorFactory.fromResource(R.drawable.redpin_marker)));
        try {
            // Tranform the string into a json object
            final JSONObject json = new JSONObject(result);
            JSONArray routeArray = json.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);
            JSONObject overviewPolylines = routes
                    .getJSONObject("overview_polyline");
            String encodedString = overviewPolylines.getString("points");
            List<LatLng> list = decodePoly(encodedString);

            for (int z = 0; z < list.size() - 1; z++) {
                LatLng src = list.get(z);
                LatLng dest = list.get(z + 1);
                line = myMap.addPolyline(new PolylineOptions()
                        .add(new LatLng(src.latitude, src.longitude),
                                new LatLng(dest.latitude, dest.longitude))
                        .width(5).color(Color.BLUE).geodesic(true));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

忽略标记,只是建议我如何添加交互式折线?


2
说交互式折线/路线是什么意思? - MaciejGórski
@MaciejGórski,感谢您的回复!我的意思是地图上绘制的蓝线不是交互式的,蓝线缺少一些像素!请看屏幕截图! - Tarsem Singh
@Tarsem 我正在创建一个样板类,让人们可以轻松地实现GDirection/polyline,并且我借用了你的一些代码。如果你不介意我使用它,请告诉我,我当然会给你信用。如果需要,你可以通过Twitter联系我:beckahsheeler。谢谢! - beckah
1
你可以使用投影 API 将其绘制为叠加层。这是关于 Android 应用程序开发的 GitHub 项目链接:https://github.com/amalChandran/trail-android - amalBit
谢谢您,decodepoly 方法帮助我解决了我的问题。 - Malick Usman
5个回答

79

不要创建太多短的 Polyline,而是像这样创建一个:

PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
for (int z = 0; z < list.size(); z++) {
    LatLng point = list.get(z);
    options.add(point);
}
line = myMap.addPolyline(options);

我也不确定当你的点彼此非常接近时,是否应该使用geodesic


2
能否检测折线的点击事件? - Muhammad Babar
3
对于可能是“是”或“否”的答案,创造一个新问题永远不是个好主意。 - Muhammad Babar
4
如果要求我的答案,那么我的回答是“是的”。 - MaciejGórski
这将只绘制一条路径。如果您希望您的路径粘附在道路上,请使用Google方向API。 - Fajar Khan
@MaciejGórski,你能帮我解决一个问题吗?如果我使用com.google.maps.model.LatLng类而不是com.google.android.gms.maps.model.LatLng类来绘制折线动画,该怎么办?这是我发布的问题链接:https://stackoverflow.com/q/48473889/7948825。 - Rakshit Sorathiya
1
你可以通过以下方式来缩小这段代码: new PolylineOptions().addAll(list).width(5).color(Color.BLUE).geodesic(true); - Gastón Saillén

27

我已经创建了几个地图教程,它们将涵盖您需要的内容。

地图动画 描述了如何根据一组LatLngs创建折线。 在地图上使用Google API:方向和地点 描述了如何使用方向API并沿着路径动画标记。

查看这两个教程以及包含示例应用程序的 Github 项目

它包含一些提示,使您的代码更清洁、更高效:

  • 使用Google HTTP库以获得更高效的API访问和易于处理JSON。
  • 使用google-map-utils库进行与地图相关的功能(例如解码折线)
  • 动画标记

11
你可以使用这种方法在谷歌地图上绘制折线
// Draw polyline on map
public void drawPolyLineOnMap(List<LatLng> list) {
    PolylineOptions polyOptions = new PolylineOptions();
    polyOptions.color(Color.RED);
    polyOptions.width(5);
    polyOptions.addAll(list);

    googleMap.clear();
    googleMap.addPolyline(polyOptions);

    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    for (LatLng latLng : list) {
        builder.include(latLng);
    }

    final LatLngBounds bounds = builder.build();

    //BOUND_PADDING is an int to specify padding of bound.. try 100.
    CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, BOUND_PADDING);
    googleMap.animateCamera(cu);
}

如果您还没有添加此行,请在gradle中添加此行。

compile 'com.google.android.gms:play-services-maps:8.4.0'

7
您应该使用options.addAll(allPoints);而不是options.add(point);

2
使用谷歌地图投影API在叠加视图上绘制折线使我们能够做很多事情。请查看此repo,其中有一个示例。

enter image description here

最初的回答已经被翻译成中文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接