How to draw free hand polygon in Google map V2 in Android?
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.
How to Draw Free Hand Shape on Google Map in Android
Here is the XML Code -
<fragment
android:id="@+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/fram_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
</FrameLayout>
Java class code -
FrameLayout fram_map;
Boolean Is_MAP_Moveable = false; // to detect map is movable
private GoogleMap googleMap;
private boolean screenLeave = false;
int source = 0;
int destination = 1;
private ArrayList<LatLng> val = new ArrayList<LatLng>();
@Nullable
@Override
public View onCreateView(){
fram_map = (FrameLayout) view.findViewById(R.id.fram_map);
fram_map.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (Is_MAP_Moveable) {
float x = event.getX();
float y = event.getY();
int x_co = Math.round(x);
int y_co = Math.round(y);
// Projection projection = googleMap.getProjection();
Point x_y_points = new Point(x_co, y_co);
LatLng latLng = googleMap.getProjection().fromScreenLocation(x_y_points);
latitude = latLng.latitude;
longitude = latLng.longitude;
HomeBean bean = new HomeBean();
bean.setPost_lat(String.valueOf(latitude));
bean.setPost_long(String.valueOf(longitude));
bean.setSource_id("3");
mLatLongList.add(bean);
System.out.println("LatLng : " + latitude + " : " + longitude);
LatLng point = new LatLng(latitude, longitude);
int eventaction = event.getAction();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
// finger touches the screen
screenLeave = false;
// System.out.println("ACTION_DOWN");
// val.add(new LatLng(latitude, longitude));
case MotionEvent.ACTION_MOVE:
// finger moves on the screen
// System.out.println("ACTION_MOVE");
/* if (val.size()==3){
val.remove(1);
}*/
val.add(new LatLng(latitude, longitude));
screenLeave = false;
Draw_Map();
case MotionEvent.ACTION_UP:
// System.out.println("ACTION_UP");
if (!screenLeave) {
screenLeave = true;
} else {
System.out.println("ACTION_UP ELSE CAse");
Is_MAP_Moveable = false; // to detect map is movable
btn_draw_State.setImageResource(R.mipmap.erase_icon);
source = 0;
destination = 1;
draw_final_polygon();
}
// finger leaves the screen
// Is_MAP_Moveable = false; // to detect map is movable
// Draw_Map();
break;
default:
break;
}
if (Is_MAP_Moveable) {
Log.e("DRAW on MAP : ", "LatLng ArrayList Size : " + mLatLongList.size());
return true;
} else {
return false;
}
} else {
return false;
}
}
});
......}
public void Draw_Map() {
// specify latitude and longitude of both source and destination Polyline
if (val.size() > 1) {
googleMap.addPolyline(new PolylineOptions().add(val.get(source), val.get(destination)).width(8).color(ContextCompat.getColor(getActivity(), R.color.colorForDrawArea)));
source++;
destination++;
}
}
private void draw_final_polygon() {
val.add(val.get(0));
PolygonOptions polygonOptions = new PolygonOptions();
polygonOptions.addAll(val);
polygonOptions.strokeColor(ContextCompat.getColor(getActivity(), R.color.colorForDrawArea));
polygonOptions.strokeWidth(8);
polygonOptions.fillColor(ContextCompat.getColor(getActivity(), R.color.colorForDrawArea));
Polygon polygon = googleMap.addPolygon(polygonOptions);
}
Android. Google map. How to draw polygon from array
I can do it.
Read LatLong from WKT and add to Array
private LatLng[] GetPolygonPoints(String polygonWkt) {
Bundle bundle = getIntent().getExtras();
wkt = bundle.getString("wkt");
ArrayList<LatLng> points = new ArrayList<LatLng>();
Pattern p = Pattern.compile("(\\d*\\.\\d+)\\s(\\d*\\.\\d+)");
Matcher m = p.matcher(wkt);
String point;
while (m.find()){
point = wkt.substring(m.start(), m.end());
points.add(new LatLng(Double.parseDouble(m.group(1)), Double.parseDouble(m.group(2))));
}
return points.toArray(new LatLng[points.size()]);
}
then draw polygon
public void Draw_Polygon() {
LatLng[] points = GetPolygonPoints(polygonWkt);
Polygon p = mMap.addPolygon(
new PolygonOptions()
.add(points)
.strokeWidth(7)
.fillColor(Color.CYAN)
.strokeColor(Color.BLUE)
);
//Calculate the markers to get their position
LatLngBounds.Builder b = new LatLngBounds.Builder();
for (LatLng point : points) {
b.include(point);
}
LatLngBounds bounds = b.build();
//Change the padding as per needed
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 20,20,5);
mMap.animateCamera(cu);
}
finally
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(MAP_TYPE_HYBRID);
mMap.getUiSettings().setRotateGesturesEnabled(false);
mMap.getUiSettings().setMapToolbarEnabled(false);
LatLng[] points = GetPolygonPoints(polygonWkt);
if (points.length >3){
Draw_Polygon();
}
else {
Add_Markers();
}
}
How to draw a shape on the map fragment by touching it using google map V2
GoogleMap
doesn't have a touch listener, so you'll have to override onTouchEvent
for the parent view of your MapFragment
. Once you have the screen coordinates of your touch event, you can get the Lat/Long by using Projection
(Doc here). Simply do
LatLng coords = mapFragment.getMap().getProjection().fromScreenLocation(point);
Where point
is a Point
describing the location of your touch event.
Once you have the LatLng
describing your touch event, you can draw shapes using either Circle
or Polygon
. Google's tutorial on drawing shapes will do a better job of explaining it than I could: Shapes - Google Maps v2
Hope this helps!
Draw a polygon in Android Map
The problem was because of the missing break in the switch
Related Topics
Android - Local Image in Webview
Out of Memory Error with Bitmap
Get Current Location of User in Android Without Using Gps or Internet
Why Does the Google Play Store Say My Android App Is Incompatible with My Own Device
Securityexception: Permission Denied (Missing Internet Permission)
How to Find Android Source Code Online
Change Drawable Color Programmatically
Reading an Image File into Bitmap from Sdcard, Why am I Getting a Nullpointerexception
No Internet on Android Emulator - Why and How to Fix
Android Studio Rendering Problems
Permanently Hide Navigation Bar in an Activity
How to Add a Dropdown Item on the Action Bar
How to Set Id of Dynamic Created Layout
How to "Select Android Sdk" in Android Studio
Change the Color of a Checked Menu Item in a Navigation Drawer