web-dev-qa-db-ja.com

AndroidのGoogleマップV2でフリーハンドポリゴンを描画する方法は?

Free Hand Polygon on the Map in Google Map V2を描きたいです。

このタスクはOverlay Map V1で可能でしたが、Google MapはV2からそのクラスを削除しました。 (このあたり Google Map V2にはRemove Overlay Class )。

Google Map V1がフリースタイルのポリゴンを描画する良い例です

Map V2では、 Google Official Doc を使用してプログラムでポリゴンを描画できますが、ユーザーはどうすればよいですか? Map V2の不明な回答 が見つかりました

シンプルなGoogleマップから始めて、プログラムでこれを行うためにポリゴンを描画し、適切に機能していますが、今はユーザーがどのように描画できるかを探していますか?ポリゴンのマーカーに基づいて描画したくありません。

// 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でそのようなことを実装するための完璧な方法は得られませんでした。

いくつかの質問

  • Map V2でフリースタイルポリゴンを描画する方法(Map V1でできるように)?
  • これを達成するためのトリックや代替手段はありますか?はい、どうですか?
  • マップ上でタッチイベントを取得してポリゴンを描画できますか?
  • Map V2で実行可能ですか?
  • 緯度経度の配列を返すタッチイベントで可能ですか?
  • setOnDragListenerの画面座標に基づいて緯度経度を取得するにはどうすればよいですか?

新しいバージョンには、古いバージョンに比べて何か特別なものがあるため、Map v2でも同じことを達成できると期待しています。

サンプルコードを提供したり、コードを投稿したりするのではなく、適切な指示とドキュメントを提供するだけです。

研究開発中に見つけたすべての文書と証拠を提供しました。

53
Chintan Khetiya

Rndで一日を過ごし、いくつかの選択肢をテストした後、解決策を見つけました。実際、同じ問題に対して2つの代替案を見つけましたが、代替案1と比較して非常に簡単なので、代替案2を使用することをお勧めします。

実際、私はAlternative 1を見つけました TheLittleNarutoAndroidHacker およびその他の開発者&Alternative 2Khan の助けを借りて、すべてに感謝します。

代替1

Map V2でフリースタイルポリゴンを描画する方法(Map V1でできること) Map V2で実行可能ですか?

はい、それは実行可能ですが、マップ上でOnTouch()OnDraw()を直接取得することはできません。そのため、これを達成するために他の方法を考えなければなりません。

この方法を達成するためのトリックや代替方法はありますか?

はい、Google Map V2は_class="com.google.Android.gms.maps.SupportMapFragment"_を使用するマップでOnTouch()またはOnDraw()をサポートしていないため、カスタムフラグメントを計画する必要があります。

タッチイベントで緯度経度の配列を返すことは可能ですか?

はい。カスタムマップフラグメントを作成して使用すると、タッチまたはドラッグイベントをマップ上に取得できます。

SetOnDragListenerの画面座標に基づいてLat-longベースを取得するにはどうすればよいですか?

setOnDragListenerは、画面座標(x、y)を返します。そのため、(x、y)LatLngに変換するいくつかの手法があり、それらには Projectionが含まれますPointLatLng

_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:
    }
});
_

どのように機能しますか?

既に述べたように、カスタムルートビューを作成する必要がありますを使用して、マップ上でタッチまたはドラッグイベントを取得できます。

ステップ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で使用する1つのインターフェイスが必要です

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:
            }
        });
    }}
_

参照 Link1Link2

ここまでで、LatLongX、Yスクリーン座標に基づいて取得できます。ここで、Arrayに保存するだけです。その配列は、マップ上での描画に使用され、最終的には自由形状のポリゴンのようになります。

enter image description here

これがあなたのお役に立てば幸いです。

更新:

代替案2

ご存知のように、フレームレイアウトは透過レイアウトなので、フレームレイアウトを使用してこれを実現しました。この場合、カスタムフラグメントを作成する必要はありません。ルートレイアウトとしてフレームレイアウトを使用しました。したがって、基本的にルートレイアウトでTouch Eventsを取得し、以前にカスタムフラグメントで取得したように、画面座標を返します。

これで、「フリードロー」内にボタンを作成しました。そのため、それをクリックすると、地図上で指を動かしてフリーハンドのポリゴンを描くことができ、画面上で地図が移動できなくなります。同じボタンを再度クリックすると、画面は理想的なモードになります。

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

ただし、描画中はリストを維持する必要があるため、以前のリストデータを消去する必要があります。

73
Chintan Khetiya

これをチェックしてください.. UはGoogle Map v2を表示できると思います

AsyncTaskの「decodePoly」および「drawPath」メソッドを確認してください

「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
    }
}

それが役に立てば幸い。乾杯!

[〜#〜] update [〜#〜]

これを確認してください.. Google Map v2フラグメント用のOnDragListenerの作成

また、これをチェックしてください.. GoogleマップV2を使用してタッチすることでマップフラグメントに図形を描画する方法

いくつかの参照.. Googleマップv2 Androidのマーカーから画面座標を取得する方法

3
AndroidHacker

そのため、マップ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そして、そのパラメーターから座標を取得します。これが役立つことを願っています:)

2
TheLittleNaruto

これは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/

1
Nguyen Thanh An