如何在路线谷歌地图v2 android上绘制交互式折线

Posted

技术标签:

【中文标题】如何在路线谷歌地图v2 android上绘制交互式折线【英文标题】:How to draw interactive Polyline on route google maps v2 android 【发布时间】:2013-06-29 19:34:13 【问题描述】:

我有以下 代码为我绘制折线并且工作正常,但问题是它没有绘制交互式折线,绘制的线缺少一些像素!

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;
    

代码工作正常,绘制从一个地方到另一个地方的路线,但没有绘制交互式路线

屏幕截图:-

我认为问题在于我的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();
        
    

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

【问题讨论】:

交互式折线/路线是什么意思? @MaciejGórski 感谢您的回复!我的意思是在地图上绘制的蓝线不是交互式的,蓝线缺少一些像素!请看屏幕截图! @Tarsem 我正在为人们创建一个样板类以轻松实现 GDirection/折线,并且我借用了您的一些代码。如果您不介意我使用它,请告诉我,我当然会感谢您。如果您需要,可以在 Twitter 上与我联系:beckahsheeler 谢谢! github.com/amalChandran/trail-android 您可以使用投影 API 将其绘制为叠加层。 感谢 decodepoly 方法帮助我解决了我的问题。 【参考方案1】:

与其创建太多简短的Polylines,不如创建一个像这里这样的:

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,因为您的点彼此如此接近。

【讨论】:

是否可以检测到对折线的点击? 我认为答案可能是YesNo。从来没有一个好主意会提出新问题。 @MuhammadBabar 那么我的答案是Yes 这只会绘制一条路径。如果你想让你的道路坚持道路使用谷歌方向 API。 您可以通过执行此 new PolylineOptions() .addAll(list).width(5).color(Color.BLUE).geodesic(true); 来缩小此代码;【参考方案2】:

我创建了几个地图教程,可以满足您的需求

Animating the map 描述了如何基于一组 LatLngs 创建折线。 Using Google APIs on your map : Directions and Places 描述了如何使用 Directions API 并沿路径为标记设置动画。

看看这 2 个教程和包含示例应用程序的 Github project。

它包含一些让您的代码更简洁、更高效的提示:

使用 Google HTTP 库实现更高效的 API 访问和轻松的 JSON 处理。 将 google-map-utils 库用于地图相关功能(如解码折线) 动画标记

【讨论】:

【参考方案3】:

您可以使用此方法在googleMap上绘制折线

// 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'

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

使用 google maps 投影 api 在叠加视图上绘制折线使我们能够做很多事情。检查这个有例子的repo。

【讨论】:

以上是关于如何在路线谷歌地图v2 android上绘制交互式折线的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中的谷歌地图上绘制路线并计算多个标记之间的距离

Android,在谷歌地图上绘制路线

谷歌地图 Android API v2 - 折线上的信息窗口?

如何使用谷歌方向 API 在苹果地图上快速绘制路线?

无法在 Android 谷歌地图上绘制路径

谷歌地图上两个位置之间的Android路线