Как нарисовать многоугольник свободной руки в Google map V2 В Android?


Я хочу нарисовать Free Hand Polygon on the Map in Google Map V2.

эта задача была возможна с Overlay Map V1 но Google Map удалил этот класс из V2. (На этой карте Google V2 есть удалить класс наложения).

хороший пример для Google Map V1, чтобы нарисовать полигон свободного стиля.

В Map V2, мы можем нарисовать полигон программно с помощью Официальный Документ Google но что делать? Я нашел неясный ответ для карты V2

Я начал с простого Google Map & draw polygon, чтобы сделать это программно, и он работает правильно, но теперь я ищу, как пользователь может рисовать? Я не хочу рисовать на основе маркера на полигоне.

// Instantiates a new Polygon object and adds points to define a rectangle
PolygonOptions rectOptions = new PolygonOptions()
              .add(new LatLng(37.35, -122.0),
                   new LatLng(37.45, -122.0),
                   new LatLng(37.45, -122.2),
                   new LatLng(37.35, -122.2),
                   new LatLng(37.35, -122.0));

// Get back the mutable Polygon
Polygon polygon = myMap.addPolygon(rectOptions);

Я сделал много исследований и разработок по этой теме, но не получил идеальный способ реализовать такую вещь в Map V2.

Несколько Вопросов

  • как рисовать фристайл полигон в карте V2 (как мы можем сделать с картой V1)?
  • есть ли какой-либо трюк или Альтернатива для достижения этого? Если да, то как?
  • можем ли мы получить сенсорное событие на карте и нарисовать полигон?
  • возможно ли это в Map V2?
  • возможно ли с сенсорным событием, которое возвращает массив lat-long?
  • как я могу получить Lat-long на основе координат экрана на setOnDragListener?

каждая новая версия имеет что-то дополнительное по сравнению со старым, поэтому я я ожидаю, что я могу достичь того же самого в Map v2 также.

Я не прошу дать мне какой-то пример кода или опубликовать ваш код, просто какое-то правильное направление и документацию.

Я предоставил все документы и доказательства, которые я нашел во время исследований и разработок.

4 52

4 ответа:

проведя целый день в Rnd и протестировав некоторые альтернативы, я нашел решение. На самом деле я нашел две альтернативы для той же проблемы, но я хотел бы предложить использование вариант 2 потому что это действительно очень легко по сравнению с Вариант 1.

на самом деле я нашел Вариант 1 С помощью TheLittleNaruto,AndroidHacker и некоторые другие разработчики & вариант 2 С помощью Хан так что спасибо всем.

Вариант 1

как нарисовать полигон свободного стиля на карте V2 (как мы можем сделать с картой V1) ? Возможно ли это в Map V2 ?

Да, это возможно, но вы не можете получить непосредственно OnTouch() & OnDraw() на карте. Поэтому мы должны придумать какой-то другой способ достичь этого.

есть ли какой-нибудь трюк или альтернативный способ добиться этого, если да, то как ?

Да, Google Map V2 не поддерживает OnTouch() или OnDraw() на карте с помощью class="com.google.android.gms.maps.SupportMapFragment" поэтому мы должны планировать для пользовательского фрагмента.

можно ли вернуть массив lat-long с сенсорным событием ?

да, если мы создадим любой пользовательский фрагмент карты и используем его, мы можем получить это Touch или перетащить событие на карте.

как я могу получить Lat-long base на экранных координатах на setOnDragListener ?

setOnDragListener возвращает экранные координаты (x,y). Теперь для этого есть несколько методов для преобразования (x,y) до LatLng и они включают в себя проекция вместе с точка & LatLng.

customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {@Override
    public void onDrag(MotionEvent motionEvent) {
        Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));
        Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));

        float x = motionEvent.getX(); // get screen x position or coordinate 
        float y = motionEvent.getY();  // get screen y position or coordinate 

        int x_co = Integer.parseInt(String.valueOf(Math.round(x))); // casting float to int 
        int y_co = Integer.parseInt(String.valueOf(Math.round(y))); // casting float to int 

        projection = mMap.getProjection(); // Will convert your x,y to LatLng
        Point x_y_points = new Point(x_co, y_co);// accept int x,y value
        LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points); // convert x,y to LatLng
        latitude = latLng.latitude; // your latitude 
        longitude = latLng.longitude; // your longitude 

        Log.i("ON_DRAG", "lat:" + latitude);
        Log.i("ON_DRAG", "long:" + longitude);

        // Handle motion event:
    }
});

как это работает ?

как у меня уже есть как уже упоминалось ранее, мы должны создать пользовательский корневой вид и используя это мы можем получить Touch или перетащить события на карте.

Шаг 1: Мы Создаем MySupportMapFragment extends SupportMapFragment и мы будем использовать его в качестве .xml-файл

 <fragment
        android:id="@+id/map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        class="pkg_name.MySupportMapFragment" /> 

Шаг 2: Создайте MapWrapperLayout extends FrameLayout так что мы можем установить нажмите или перетащите слушателя внутри и встроить его вид с видом на карту. Итак, нам нужен один интерфейс, который мы будем использовать в Root_Map.java

MySupportMapFragment.Java

public class MySupportMapFragment extends SupportMapFragment {
    public View mOriginalContentView;
    public MapWrapperLayout mMapWrapperLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

        mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
        mMapWrapperLayout = new MapWrapperLayout(getActivity());
        mMapWrapperLayout.addView(mOriginalContentView);
        return mMapWrapperLayout;
    }

    @Override
    public View getView() {
        return mOriginalContentView;
    }

    public void setOnDragListener(MapWrapperLayout.OnDragListener onDragListener) {
        mMapWrapperLayout.setOnDragListener(onDragListener);
    }
}

MapWrapperLayout.java

    public class MapWrapperLayout extends FrameLayout {
     private OnDragListener mOnDragListener;

     public MapWrapperLayout(Context context) {
         super(context);
     }

     public interface OnDragListener {
         public void onDrag(MotionEvent motionEvent);
     }

     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (mOnDragListener != null) {
             mOnDragListener.onDrag(ev);
         }
         return super.dispatchTouchEvent(ev);
     }

     public void setOnDragListener(OnDragListener mOnDragListener) {
         this.mOnDragListener = mOnDragListener;
     }

 }

Root_Map.Java

public class Root_Map extends FragmentActivity {

    private GoogleMap mMap;
    public static boolean mMapIsTouched = false;
    MySupportMapFragment customMapFragment;
    Projection projection;
    public double latitude;
    public double longitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.root_map);
        MySupportMapFragment customMapFragment = ((MySupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
        mMap = customMapFragment.getMap();

        customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {               @Override
            public void onDrag(MotionEvent motionEvent) {
                Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));
                Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));

                float x = motionEvent.getX();
                float y = motionEvent.getY();

                int x_co = Integer.parseInt(String.valueOf(Math.round(x)));
                int y_co = Integer.parseInt(String.valueOf(Math.round(y)));

                projection = mMap.getProjection();
                Point x_y_points = new Point(x_co, y_co);
                LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);
                latitude = latLng.latitude;
                longitude = latLng.longitude;

                Log.i("ON_DRAG", "lat:" + latitude);
                Log.i("ON_DRAG", "long:" + longitude);

                // Handle motion event:
            }
        });
    }}

ссылка Link1,Link2

до сюда я могу добраться LatLong на основе координаты экрана X,Y. Теперь я просто должен хранить его в массив. Этот массив будет используется для рисования на карте и, наконец, он будет выглядеть как полигон свободной формы.

enter image description here

я надеюсь, что это определенно поможет вам.

обновление:

вариант 2

как известно, каркас макета является прозрачным макетом, поэтому я достиг этого с помощью макета кадра. В этом случае нет необходимости создавать пользовательский фрагмент. Я только что использовал рама Макет как корневой макет. Так что в основном я получу Сенсорные События в корневом макете, и это вернет координаты экрана, как мы получили в пользовательском фрагменте ранее.

теперь я создал кнопку внутри"Free Draw". Поэтому, когда вы нажимаете на это, вы можете перемещать пальцы по карте и рисовать полигон свободной руки, и это отключит вашу карту, перемещающуюся на экране. При повторном нажатии на ту же кнопку, экран идет в идеале режим.

root_map.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <fragment
        android:id="@+id/map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />

    <FrameLayout
        android:id="@+id/fram_map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <Button
            android:id="@+id/btn_draw_State"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Free Draw" />
    </FrameLayout>

</FrameLayout>

Root_Map.java

FrameLayout fram_map = (FrameLayout) findViewById(R.id.fram_map);
Button btn_draw_State = (Button) findViewById(R.id.btn_draw_State);
Boolean Is_MAP_Moveable = false; // to detect map is movable 

// кнопка изменит подвижное состояние карты

btn_draw_State.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Is_MAP_Moveable = !Is_MAP_Moveable;
    }
});

Нажмите кнопку макета кадра и с помощью сделать некоторые задачи

fram_map.setOnTouchListener(new View.OnTouchListener() {     @Override
    public boolean onTouch(View v, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        int x_co = Math.round(x);
        int y_co = Math.round(y);

        projection = mMap.getProjection();
        Point x_y_points = new Point(x_co, y_co);

        LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);
        latitude = latLng.latitude;

        longitude = latLng.longitude;

        int eventaction = event.getAction();
        switch (eventaction) {
            case MotionEvent.ACTION_DOWN:
                // finger touches the screen
                val.add(new LatLng(latitude, longitude));

            case MotionEvent.ACTION_MOVE:
                // finger moves on the screen
                val.add(new LatLng(latitude, longitude));

            case MotionEvent.ACTION_UP:
                // finger leaves the screen
                Draw_Map();
                break;
        }

        return Is_MAP_Moveable;

    }
});

// нарисовать карту

public void Draw_Map() {
    rectOptions = new PolygonOptions();
    rectOptions.addAll(val);
    rectOptions.strokeColor(Color.BLUE);
    rectOptions.strokeWidth(7);
    rectOptions.fillColor(Color.CYAN);
    polygon = mMap.addPolygon(rectOptions);
}

тем не менее, теперь вы должны поддерживать свой список во время рисования, так что вы должны очистить ваши предыдущие данные списка.

зацени .. Я считаю, что вы способны показать Google Map v2

Проверьте" decodePoly "и" drawPath " метод в AsyncTask

основной Imphasis в "drawPath"..

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);

полный класс для вашей справки ..

package com.example.androidhackergooglemap;

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.Marker;
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.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class MainActivity extends FragmentActivity implements OnClickListener {

    private GoogleMap myMap;
    Polyline line;
    Context context;

    Location location;
    boolean check_provider_enabled = false;

    // 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.activity_main);
        context = MainActivity.this;

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

        LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
        boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
        location = service.getLastKnownLocation(LocationManager.GPS_PROVIDER);

        // check if enabled and if not send user to the GSP settings
        // Better solution would be to display a dialog and suggesting to 
        // go to the settings
        if (!enabled) {
          /*Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
          startActivity(intent);*/
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
            Toast.makeText(getApplicationContext(), "Enable GPS servcies to use this app.", Toast.LENGTH_LONG).show();
        } else{


            try{

                String urlTopass = makeURL(startLatLng.latitude,
                        startLatLng.longitude, endLatLng.latitude,
                        endLatLng.longitude);
                new connectAsyncTask(urlTopass).execute();

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

        }





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


    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.ic_launcher)));
        myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
                BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
        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);

            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);

            /*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;
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub

    }
}

надеюсь, что это помогает. Ура!

обновление

проверить это .. создание OnDragListener для Google Map V2 фрагмент

также проверьте это .. как нарисовать фигуру на фрагменте карты, коснувшись его с помощью google map V2

еще несколько ссылок .. как получить координаты экрана от маркера в google maps v2 android

таким образом, у нас есть некоторое решение для свободной руки рисовать на карте v2. Реализовать GoogleMap.OnMarkerDragListener в вашей деятельности карты . Он переопределит функцию onMarkerDrag.

@Override
public void onMarkerDrag(Marker marker) {

   //add the marker's latlng in a arraylist of LatLng and pass it to the loop
    for (int i = 0; i < arraylistoflatlng.size(); i++) {
         myMap.addPolyline(new PolylineOptions()
        .addAll(arraylistoflatlng)
        .width(5)
        .color(Color.RED));
    }
    }

вы можете передать какой-то хак для свободной руки, как только пользователь коснется карты, вам нужно будет обнаружить эти координаты и передать их в onMarkerDrag . Как вам придется использовать информацию области для дальнейшего процесса. Для сенсорного события вы можете реализовать GoogleMap.OnMapClickListener и получить координаты от его параметра. Надеюсь, это поможет:)

это google maps API v2 учебник:

public class MapPane extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map_activity);
        GoogleMap map = ((MapFragment) getFragmentManager()
                .findFragmentById(R.id.map)).getMap();

        map.moveCamera(CameraUpdateFactory.newLatLngZoom(
                new LatLng(-18.142, 178.431), 2));

        // Polylines are useful for marking paths and routes on the map.
        map.addPolyline(new PolylineOptions().geodesic(true)
                .add(new LatLng(-33.866, 151.195))  // Sydney
                .add(new LatLng(-18.142, 178.431))  // Fiji
                .add(new LatLng(21.291, -157.821))  // Hawaii
                .add(new LatLng(37.423, -122.091))  // Mountain View
        );
    }
}

Ссылка:https://developers.google.com/maps/documentation/android/