如何在Android的谷歌地图V2中绘制手绘多边形? [英] How to draw free hand polygon in Google map V2 in Android?

查看:43
本文介绍了如何在Android的谷歌地图V2中绘制手绘多边形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 Google Map V2 中的地图上绘制 Free Hand Polygon.

使用 Overlay Map V1 可以完成此任务,但 Google Map 已从 V2 中删除了该类.(根据这个 Google Map V2 已删除覆盖类).

Google Map V1 绘制自由多边形的好例子.

<块引用>

在 Map V2 中,我们可以借助 Google 官方文档以编程方式绘制多边形 但是用户应该怎么做?我发现 Map V2 的答案不明确

我从简单的 Google Map & 开始绘制多边形以编程方式执行此操作它工作正常,但现在我正在寻找用户如何绘制?我不想根据多边形上的标记进行绘制.

//实例化一个新的 Polygon 对象并添加点来定义一个矩形PolygonOptions rectOptions = new PolygonOptions().add(new LatLng(37.35, -122.0),新的纬度(37.45,-122.0),新的纬度(37.45,-122.2),新的纬度(37.35,-122.2),新的纬度(37.35,-122.0));//取回可变多边形多边形多边形 = myMap.addPolygon(rectOptions);

我在这个主题上做了很多研究和开发,但没有找到在 Map V2 中实现这种事情的完美方法.

一些问题

  • 如何在 Map V2 中绘制自由式多边形(就像我们在 Map V1 中所做的那样)?
  • 是否有任何技巧或替代方法可以实现这一目标?如果是,如何?
  • 我们可以在地图上获取触摸事件吗?绘制多边形?
  • 在 Map V2 中是否可行?
  • 是否可以使用返回经纬度数组的触摸事件?
  • 如何根据 setOnDragListener 上的屏幕坐标获取经纬度?

与旧版本相比,每个新版本都有一些额外的东西,所以我希望我也可以在 Map v2 中实现相同的功能.

我不是要给我一些示例代码或发布您的代码,只是一些正确的方向和文档.

我已经提供了我在研究和开发过程中发现的所有文件和证据.

解决方案

在 Rnd 中度过一整天并测试了一些替代方案后,我找到了解决方案.实际上,我为同一问题找到了两种替代方案,但我建议使用替代方案 2,因为与替代方案 1 相比,这确实非常容易.

实际上我在 TheLittleNaruto 的帮助下找到了替代方案 1AndroidHacker 和其他一些开发人员 &替代方案 2Khan 的帮助下,非常感谢大家.

备选方案 1

<块引用>

如何在 Map V2 中绘制自由样式的多边形(就像我们在 Map V1 中所做的那样)?Map V2中可行吗?

是的,这是可行的,但您不能直接获得 OnTouch() &OnDraw() 在地图上.因此,我们必须考虑其他方式来实现这一目标.

<块引用>

是否有任何技巧或替代方法可以实现这一目标,如果是,如何?

是的,Google Map V2 在使用 class="com.google.android 的地图上不支持 OnTouch()OnDraw().gms.maps.SupportMapFragment" 所以我们必须计划一个自定义的 Fragment.

<块引用>

是否可以通过触摸事件返回经纬度数组?

是的,如果我们创建任何自定义地图片段并使用它,我们可以在地图上获得 TouchDrag 事件.

<块引用>

如何根据 setOnDragListener 上的屏幕坐标获取经纬度?

setOnDragListener 将返回屏幕坐标 (x,y).现在,有一些技术可以将 (x,y) 转换为 LatLng,它们包括 Projection 以及 Point &LatLng.

customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {@Overridepublic void onDrag(MotionEvent motionEvent) {Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));浮动 x = motionEvent.getX();//获取屏幕 x 位置或坐标浮动 y = motionEvent.getY();//获取屏幕 y 位置或坐标int x_co = Integer.parseInt(String.valueOf(Math.round(x)));//将 float 转换为 intint y_co = Integer.parseInt(String.valueOf(Math.round(y)));//将 float 转换为 int投影 = mMap.getProjection();//将您的 x,y 转换为 LatLngPoint x_y_points = new Point(x_co, y_co);//接受int x,y值LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);//将 x,y 转换为 LatLng纬度 = latLng.latitude;//你的纬度经度 = latLng.longitude;//你的经度Log.i(ON_DRAG",纬度:"+纬度);Log.i(ON_DRAG",long:"+经度);//处理动作事件:}});

<块引用>

它是如何工作的?

正如我之前已经提到的,我们必须创建一个自定义根视图,并使用它我们可以获得触摸拖动事件地图.

第 1 步:我们创建 MySupportMapFragment extends SupportMapFragment 并将其用作我们的 .xml 文件

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

第2步:创建一个MapWrapperLayout extends FrameLayout,这样我们就可以在里面设置一个Touch or Drag listener,并将其视图嵌入到地图视图中.所以,我们需要一个我们将在 Root_Map.java 中使用的接口

MySupportMapFragment.Java

public class MySupportMapFragment extends SupportMapFragment {公共视图 mOriginalContentView;公共 MapWrapperLayout mMapWrapperLayout;@覆盖公共视图 onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);mMapWrapperLayout = new MapWrapperLayout(getActivity());mMapWrapperLayout.addView(mOriginalContentView);返回 mMapWrapperLayout;}@覆盖公共视图 getView() {返回 mOriginalContentView;}public void setOnDragListener(MapWrapperLayout.OnDragListener onDragListener) {mMapWrapperLayout.setOnDragListener(onDragListener);}}

MapWrapperLayout.java

 public class MapWrapperLayout extends FrameLayout {私有 OnDragListener mOnDragListener;公共 MapWrapperLayout(上下文上下文){超级(上下文);}公共接口 OnDragListener {public void onDrag(MotionEvent motionEvent);}@覆盖公共布尔 dispatchTouchEvent(MotionEvent ev) {如果(mOnDragListener != null){mOnDragListener.onDrag(ev);}返回 super.dispatchTouchEvent(ev);}公共无效 setOnDragListener(OnDragListener mOnDragListener) {this.mOnDragListener = mOnDragListener;}}

Root_Map.Java

public class Root_Map extends FragmentActivity {私人谷歌地图 mMap;public static boolean mMapIsTouched = false;MySupportMapFragment customMapFragment;投影投影;公共双纬度;公共双经度;@覆盖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() { @Overridepublic void onDrag(MotionEvent motionEvent) {Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));浮动 x = motionEvent.getX();浮动 y = motionEvent.getY();int x_co = Integer.parseInt(String.valueOf(Math.round(x)));int y_co = Integer.parseInt(String.valueOf(Math.round(y)));投影 = mMap.getProjection();点 x_y_points = new Point(x_co, y_co);LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);纬度 = latLng.latitude;经度 = latLng.longitude;Log.i(ON_DRAG",纬度:"+纬度);Log.i(ON_DRAG",long:"+经度);//处理动作事件:}});}}

参考 Link1Link2

到目前为止,我可以根据 X,Y 屏幕坐标获得 LatLong.现在我只需要将它存储在 Array 中.该数组将用于在地图上绘制,最终看起来像一个自由形状的多边形.

<块引用>

希望这对你有帮助.

更新:

备选方案 2

众所周知,框架布局是一种透明布局,因此我使用框架布局实现了这一点.在这种情况下,无需创建自定义片段.我刚刚使用 Frame Layout 作为根布局.所以基本上我会在根布局中获得触摸事件,这将返回屏幕坐标,正如我们之前在自定义片段中获得的那样.

现在,我在自由抽奖"中创建了一个按钮.因此,当您单击它时,您可以在地图上移动手指并绘制一个徒手多边形,这将使您的地图无法在屏幕上移动.当您再次单击同一按钮时,屏幕将进入理想模式.

root_map.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";android:layout_width=fill_parent"android:layout_height=fill_parent"><片段android:id="@+id/map";android:layout_width=fill_parent"android:layout_height=fill_parent"class=com.google.android.gms.maps.SupportMapFragment"/><框架布局android:id="@+id/frame_map";android:layout_width=fill_parent"android:layout_height=fill_parent"><按钮android:id=@+id/btn_draw_State"android:layout_width="wrap_content";android:layout_height="wrap_content";android:text="免费抽奖";/></FrameLayout></FrameLayout>

Root_Map.java

FrameLayout fram_map = (FrameLayout) findViewById(R.id.fram_map);按钮 btn_draw_State = (Button) findViewById(R.id.btn_draw_State);布尔值 Is_MAP_Moveable = false;//检测地图是否可移动

//按钮会改变地图可移动状态

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

点击框架布局并借助执行任务

fram_map.setOnTouchListener(new View.OnTouchListener() { @Override公共布尔 onTouch(查看 v,MotionEvent 事件){浮动 x = event.getX();浮动 y = event.getY();int x_co = Math.round(x);int y_co = Math.round(y);投影 = mMap.getProjection();点 x_y_points = new Point(x_co, y_co);LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);纬度 = latLng.latitude;经度 = latLng.longitude;int eventaction = event.getAction();开关(事件动作){案例 MotionEvent.ACTION_DOWN://手指触摸屏幕val.add(new LatLng(latitude, longitude));案例 MotionEvent.ACTION_MOVE://手指在屏幕上移动val.add(new LatLng(latitude, longitude));案例 MotionEvent.ACTION_UP://手指离开屏幕Draw_Map();休息;}返回 Is_MAP_Moveable;}});

//绘制地图

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

然而,现在您必须在绘制时维护您的列表,因此您必须清除之前的列表数据.

I want to draw a Free Hand Polygon on the Map in Google Map V2.

This task was possible with Overlay Map V1 but Google Map has removed that class from V2. (Per this Google Map V2 has Remove Overlay Class).

Good Example for Google Map V1 to draw free style polygon.

In Map V2, we can draw a polygon programmatically with the help of Google Official Doc but what should a user do? I have found Unclear answer for Map V2

I started with simple Google Map & draw polygon to do this programmatically & it is working properly but now I am looking for how a user can draw? I don't want to draw based on the marker on the 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);

I have done lots of Research and Development on this topic but didn't get a perfect way to implement such a thing in Map V2.

Some Questions

  • How to draw freestyle polygon in Map V2 (as we can do with Map V1)?
  • Is there any trick or alternative to achieve this? If yes how?
  • Can we get a touch event on the map & draw polygon?
  • Is it feasible in Map V2?
  • Is it possible with a touch event which returns array of lat-long?
  • How can I get Lat-long based on screen coordinates on setOnDragListener?

Each new version has something extra compared to the older one so I am expecting that I can achieve the same thing in Map v2 also.

I am not asking to give me some sample code or post your code, just some proper direction & documentation.

I have provided all documents and evidence I found during the Research and Development.

解决方案

After spending a whole day in Rnd and testing some alternatives I have found a solution. Actually I have found two alternatives for the same issue but I would like to suggest the using of Alternative 2 because that is really very easy compared to Alternative 1.

Actually I have found Alternative 1 with the help of TheLittleNaruto , AndroidHacker and some other developers & Alternative 2 with the help of Khan so thanks to all.

Alternative 1

How to Draw Free style polygon in Map V2 (as we can do with Map V1) ? Is it feasible in Map V2 ?

Yes, that is feasible but you can't get directly OnTouch() & OnDraw() on the map. So we must have to think some other way to achieve this.

Is there any trick or alternative way to achieve this thing , if yes how ?

Yes, Google Map V2 doesn't support OnTouch() or OnDraw() on a Map using class="com.google.android.gms.maps.SupportMapFragment" so we have to plan for a custom Fragment.

Is it possible to return array of lat-long with touch event ?

Yes, if we create any custom map fragment and use it we can get that Touch or Drag event over the map.

How can I get Lat-long base on screen coordinates on setOnDragListener ?

setOnDragListener will return screen coordinates (x,y). Now for that, there are some techniques to convert (x,y) to LatLng and they include Projection along with Point & 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:
    }
});

How does it work ?

As I have already mentioned before, we have to create a custom root view and using that we can get Touch or Drag Events over the map.

Step 1: We Create MySupportMapFragment extends SupportMapFragment and we will use that as our .xml file

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

Step 2: Create a MapWrapperLayout extends FrameLayout so that we can set a Touch or Drag listener inside and embed its view with map view. So, we need one Interface which we will use in 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:
            }
        });
    }}

Reference Link1 , Link2

Up to here I am able to get LatLong based on X,Y screen coordinates. Now I just have to store it in Array. That array will be used for drawing on the map and finally it will look like a free shape polygon.

I hope this will definitely help you.

Update:

Alternative 2

As we know, Frame layout is a transparent layout so I have achieved this using Frame Layout. In this case, there is no need to create a custom fragment. I have just used Frame Layout as root layout. So basically I will get Touch Events in the root layout and that will return screen coordinates, as we got in custom fragment previously.

Now, I have created a Button inside the "Free Draw". So when you click on that you can move your fingers on the map and draw a free hand polygon and that will disable your map being movable on screen. When you re-click the same button, the screen goes in ideal mode.

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 

// Button will change Map movable state

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

Touch Click of Frame Layout and with the help of the do some task

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;

    }
});

// Draw your map

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

Yet, now you have to maintain your list while you draw, so you have to clear your previous list data.

这篇关于如何在Android的谷歌地图V2中绘制手绘多边形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆