In the Google map V2, groundoverlay function has been added. The overlay on Google map is nothing but image overlays which are tied to coordinates. And when you drag or zoom into the map, they move. The Android Google map custom overlay is basically an image that is being fixed on map.
The Google Map Image Overlay allows Android Developers to fix a single image at one area on the Google map. However this is not the only functionality it provides, you can also implement a drawable map in your Android app.
In this Android app tutorial, we’re going to demonstrate one demo in which, you’ll be able to integrate Google maps with a drawable function to discover the desired places in the particular area.
Getting Started
First, you’ll need to integrate Google maps in your Android application. For this, you can read our article on how to integrate Google maps to obtain current location.
Next, go to the developer console.
Now to track drawing on the map, Extend SupportMapFragment for tracking touch.
public class MapFragment extends SupportMapFragment { private OnTouchListener mListener; public class TouchableWrapper extends FrameLayout { public TouchableWrapper(Context context) { super(context); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mListener.onTouch(); break; case MotionEvent.ACTION_UP: mListener.onTouch(); break; } return super.dispatchTouchEvent(event); } }
After tracking the touch, use Drawingpanel to draw touch point on canvas.
public class DrawingPanel extends View implements View.OnTouchListener for (Path p : paths) { canvas.drawPath(p, mPaint); }
Add Dependency in .gradle file.
//For animation compile 'com.daimajia.androidanimations:library:1.1.2@aar' compile 'com.nineoldandroids:library:2.4.0' // For map calculations compile 'com.google.maps.android:android-maps-utils:0.3.4'
Next, add tracking in Activity.
once map loaded implement draglistner of drawing panel.
1. initialize drawing panel
private FrameLayout flMapContainer; private DrawingPanel drawingpanel; flMapContainer = (FrameLayout) findViewById(R.id.flMapContainer); drawingpanel = new DrawingPanel(this); drawingpanel.setVisibility(View.GONE); drawingpanel.setBackgroundColor(Color.parseColor("#50000000")); flMapContainer.addView(drawingpanel);
2. Set Draging listner
drawingpanel.setOnDragListener(new DrawingPanel.OnDragListener() { @Override public void onDragEvent(MotionEvent motionEvent) {
3. Get details from ACTION_DOWN, ACTION_MOVE
//declared variable private ArrayList<LatLng> latLngs; private Projection projection; private GoogleMap mMap; //Track touch point 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))); //get Projection from google map projection = mMap.getProjection(); Point x_y_points = new Point(x_co, y_co); LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points); if (latLngs == null) public LatLngBounds toBounds(LatLng center, double radius) { LatLng southwest = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 225); LatLng northeast = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 45); return new LatLngBounds(southwest, northeast); } latLngs = new ArrayList<LatLng>(); latLngs.add(latLng);
4. Get details from ACTION_UP
private PolygonOptions polygonOptions; private LatLngBounds bounds; double maxDistanceFromCenter; private LatLng latLng; private LatLngBounds latLngBounds; //Join all points and draw polygon polygonOptions.strokeWidth(10); polygonOptions.strokeColor(ContextCompat.getColor(MapActivity.this, R.color.colorPrimary)); polygonOptions.addAll(latLngs); mMap.addPolygon(polygonOptions); drawingpanel.setVisibility(View.GONE); //find radius and center from drawing LatLng latLng1 = getPolygonCenterPoint(latLngs); LatLng latLngxmin = projection.fromScreenLocation(drawingpanel.getPointXMin()); LatLng latLngxmax = projection.fromScreenLocation(drawingpanel.getPointxMax()); LatLng latLngymin = projection.fromScreenLocation(drawingpanel.getPointYmin()); LatLng latLngymax = projection.fromScreenLocation(drawingpanel.getPointYmax()); if (drawingpanel.getPointXMin().x != 0 && drawingpanel.getPointXMin().y != 0) maxDistanceFromCenter = distance(latLng1.latitude, latLng1.longitude, latLngxmin.latitude, latLngxmin.longitude); double tempdistance = 0; if (drawingpanel.getPointxMax().x != 0 && drawingpanel.getPointxMax().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngxmax.latitude, latLngxmax.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; if (drawingpanel.getPointYmin().x != 0 && drawingpanel.getPointYmin().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngymin.latitude, latLngymin.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; if (drawingpanel.getPointYmax().x != 0 && drawingpanel.getPointYmax().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngymax.latitude, latLngymax.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; drawingpanel.clear();
5. Get LatLngBounds to check marker is in or not
public LatLngBounds toBounds(LatLng center, double radius) { LatLng southwest = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 225); LatLng northeast = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 45); return new LatLngBounds(southwest, northeast); }
Want To Develop An Android Application?
Book your free consultation with Android app experts.
Start Code Integration
- Constants.java
public class Constants { public static final String[] name = {"The Chocolate Room", "A One Tea Stall", "Ashapura Tea Stall", "ShivShakti Tea Stall"}; public static final double[] lat = {23.022505, 23.0246724, 23.0249171, 23.0234268}; public static final double[] lng = {72.571362, 72.572015, 72.57047, 72.56666}; }
- MapFragment.java
public class MapFragment extends SupportMapFragment { private OnTouchListener mListener; @Override public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) { View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance); TouchableWrapper frameLayout = new TouchableWrapper(getActivity()); frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent)); ((ViewGroup) layout).addView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return layout; } public void setListener(OnTouchListener listener) { mListener = listener; } public interface OnTouchListener { public abstract void onTouch(); } public class TouchableWrapper extends FrameLayout { public TouchableWrapper(Context context) { super(context); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mListener.onTouch(); break; case MotionEvent.ACTION_UP: mListener.onTouch(); break; } return super.dispatchTouchEvent(event); } } }
- DrawingPanel.java
public class DrawingPanel extends View implements View.OnTouchListener { private static final String TAG = "DrawView"; private Canvas mCanvas; private Path mPath; private Paint mPaint; private LinkedList<Path> paths = new LinkedList<Path>(); private Context mContext; private OnDragListener onDragListener; private Point pointXMin, pointYmin, pointxMax, pointYmax; public interface OnDragListener { void onDragEvent(MotionEvent motionEvent); } public OnDragListener getOnDragListener() { return onDragListener; } public void setOnDragListener(OnDragListener onDragListener) { this.onDragListener = onDragListener; } public DrawingPanel(Context context) { super(context); mContext = context; setFocusable(true); setFocusableInTouchMode(true); this.setOnTouchListener(this); pointXMin = new Point(); pointYmin = new Point(); pointxMax = new Point(); pointYmax = new Point(); pointXMin.set(0, 0); pointYmin.set(0, 0); pointxMax.set(0, 0); pointYmax.set(0, 0); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(ContextCompat.getColor(context, R.color.colorPrimary)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(10); mCanvas = new Canvas(); mPath = new Path(); paths.add(mPath); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { for (Path p : paths) { canvas.drawPath(p, mPaint); } } private float mX, mY; private static final float TOUCH_TOLERANCE = 4; private void touch_start(float x, float y) { mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touch_move(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touch_up() { mPath.lineTo(mX, mY); // commit the path to our offscreen mCanvas.drawPath(mPath, mPaint); // kill this so we don't double draw mPath = new Path(); paths.add(mPath); } @Override public boolean onTouch(View arg0, MotionEvent event) { float x = event.getX(); float y = event.getY(); if (pointXMin.x == 0) { pointXMin.x = (int) x; pointXMin.y = (int) y; pointxMax.x = (int) x; pointxMax.y = (int) y; pointYmin.x = (int) x; pointYmin.y = (int) y; pointYmin.x = (int) x; pointYmin.y = (int) y; } if (pointXMin.x > x) { pointXMin.x = (int) x; pointXMin.y = (int) y; } if (pointYmin.y > y) { pointYmin.x = (int) x; pointYmin.y = (int) y; } if (pointxMax.x < x) { pointxMax.x = (int) x; pointxMax.y = (int) y; } if (pointYmax.y < y) { pointYmax.x = (int) x; pointYmax.y = (int) y; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touch_start(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); invalidate(); break; } onDragListener.onDragEvent(event); return true; } public void clear() { paths.clear(); pointXMin.set(0, 0); pointYmin.set(0, 0); pointxMax.set(0, 0); pointYmax.set(0, 0); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(ContextCompat.getColor(mContext, R.color.colorPrimary)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(10); mCanvas = new Canvas(); mPath = new Path(); paths.add(mPath); } public Point getPointXMin() { return pointXMin; } public void setPointXMin(Point pointXMin) { this.pointXMin = pointXMin; } public Point getPointYmin() { return pointYmin; } public void setPointYmin(Point pointYmin) { this.pointYmin = pointYmin; } public Point getPointxMax() { return pointxMax; } public void setPointxMax(Point pointxMax) { this.pointxMax = pointxMax; } public Point getPointYmax() { return pointYmax; } public void setPointYmax(Point pointYmax) { this.pointYmax = pointYmax; } }
- MapActivity.java
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback { private FrameLayout flMapContainer; private GoogleMap mMap; private ProgressBar progressBar; private LinearLayout llMapActionContainer; private DrawingPanel drawingpanel; private ArrayList<LatLng> latLngs; private PolygonOptions polygonOptions; private Projection projection; private LatLngBounds bounds; double maxDistanceFromCenter; private LatLng latLng; private LatLngBounds latLngBounds; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); initControls(); } private void initControls() { // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(map); mapFragment.getMapAsync(this); progressBar = (ProgressBar) findViewById(R.id.progressBar); progressBar.setVisibility(View.GONE); progressBar.getIndeterminateDrawable() .setColorFilter(ContextCompat.getColor(this, R.color.colorPrimary), PorterDuff.Mode.SRC_IN); llMapActionContainer = (LinearLayout) findViewById(R.id.llMapActionContainer); flMapContainer = (FrameLayout) findViewById(R.id.flMapContainer); drawingpanel = new DrawingPanel(this); drawingpanel.setVisibility(View.GONE); drawingpanel.setBackgroundColor(Color.parseColor("#50000000")); flMapContainer.addView(drawingpanel); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; ((MapFragment) getSupportFragmentManager().findFragmentById(map)).setListener(new MapFragment.OnTouchListener() { @Override public void onTouch() { if (llMapActionContainer.getVisibility() == View.GONE) { llMapActionContainer.setVisibility(View.VISIBLE); YoYo.with(Techniques.FadeIn).playOn(llMapActionContainer); setFadeOutAfterSomeTime(); } } }); mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { if (mMap != null) { addMarkers(); } } }); drawingpanel.setOnDragListener(new DrawingPanel.OnDragListener() { @Override public void onDragEvent(MotionEvent motionEvent) { //Track touch point 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))); //get Projection from google map projection = mMap.getProjection(); Point x_y_points = new Point(x_co, y_co); LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points); if (latLngs == null) latLngs = new ArrayList<LatLng>(); latLngs.add(latLng); if (motionEvent.getAction() == MotionEvent.ACTION_UP) { mMap.clear(); //Join all points and draw polygon polygonOptions.strokeWidth(10); polygonOptions.strokeColor(ContextCompat.getColor(MapActivity.this, R.color.colorPrimary)); polygonOptions.addAll(latLngs); mMap.addPolygon(polygonOptions); drawingpanel.setVisibility(View.GONE); //find radius and center from drawing LatLng latLng1 = getPolygonCenterPoint(latLngs); LatLng latLngxmin = projection.fromScreenLocation(drawingpanel.getPointXMin()); LatLng latLngxmax = projection.fromScreenLocation(drawingpanel.getPointxMax()); LatLng latLngymin = projection.fromScreenLocation(drawingpanel.getPointYmin()); LatLng latLngymax = projection.fromScreenLocation(drawingpanel.getPointYmax()); if (drawingpanel.getPointXMin().x != 0 && drawingpanel.getPointXMin().y != 0) maxDistanceFromCenter = distance(latLng1.latitude, latLng1.longitude, latLngxmin.latitude, latLngxmin.longitude); double tempdistance = 0; if (drawingpanel.getPointxMax().x != 0 && drawingpanel.getPointxMax().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngxmax.latitude, latLngxmax.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; if (drawingpanel.getPointYmin().x != 0 && drawingpanel.getPointYmin().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngymin.latitude, latLngymin.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; if (drawingpanel.getPointYmax().x != 0 && drawingpanel.getPointYmax().y != 0) tempdistance = distance(latLng1.latitude, latLng1.longitude, latLngymax.latitude, latLngymax.longitude); if (tempdistance > maxDistanceFromCenter) maxDistanceFromCenter = tempdistance; drawingpanel.clear(); latLngBounds = toBounds(latLng, maxDistanceFromCenter); addMarkers(); } } }); } private void addMarkers() { int count = 0; mMap.clear(); LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (int index = 0; index < Constants.lat.length; index++) { LatLng marker = new LatLng(Constants.lat[index], Constants.lng[index]); if (latLngBounds != null) { if (latLngBounds.contains(marker)) mMap.addMarker(new MarkerOptions().position(marker).title(Constants.name[index])); } else { mMap.addMarker(new MarkerOptions().position(marker).title(Constants.name[index])); builder.include(marker); count++; } } if (count > 0 && latLngBounds == null) { LatLngBounds bounds = builder.build(); CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 80); mMap.animateCamera(cu); } } private LatLng getPolygonCenterPoint(ArrayList<LatLng> polygonPointsList) { LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (int i = 0; i < polygonPointsList.size(); i++) { builder.include(polygonPointsList.get(i)); } bounds = builder.build(); latLng = bounds.getCenter(); return latLng; } private double distance(double lat1, double lon1, double lat2, double lon2) { Location selected_location = new Location("locationA"); selected_location.setLatitude(lat1); selected_location.setLongitude(lon1); Location near_locations = new Location("locationA"); near_locations.setLatitude(lat2); near_locations.setLongitude(lon2); double distance = selected_location.distanceTo(near_locations); return distance; } public LatLngBounds toBounds(LatLng center, double radius) { LatLng southwest = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 225); LatLng northeast = SphericalUtil.computeOffset(center, radius * Math.sqrt(2.0), 45); return new LatLngBounds(southwest, northeast); } private void setFadeOutAfterSomeTime() { new Handler().postDelayed(new Runnable() { @Override public void run() { YoYo.with(Techniques.FadeOut).withListener(new com.nineoldandroids.animation.Animator.AnimatorListener() { @Override public void onAnimationStart(com.nineoldandroids.animation.Animator animation) { } @Override public void onAnimationEnd(com.nineoldandroids.animation.Animator animation) { llMapActionContainer.setVisibility(View.GONE); } @Override public void onAnimationCancel(com.nineoldandroids.animation.Animator animation) { } @Override public void onAnimationRepeat(com.nineoldandroids.animation.Animator animation) { } }).playOn(llMapActionContainer); } }, 10000); } public void onRedoSearchClick(View view) { if (latLngs != null) latLngs.clear(); mMap.clear(); VisibleRegion visibleRegion = mMap.getProjection().getVisibleRegion(); LatLngBounds latLngBounds = visibleRegion.latLngBounds; latLng = latLngBounds.getCenter(); maxDistanceFromCenter = distance(latLngBounds.getCenter().latitude, latLngBounds.getCenter().longitude, visibleRegion.farRight.latitude, visibleRegion.farRight.longitude); this.latLngBounds = null; addMarkers(); } public void onDrawOnMapClick(View view) { if (latLngs != null) latLngs.clear(); mMap.clear(); llMapActionContainer.setVisibility(View.GONE); drawingpanel.setVisibility(View.VISIBLE); drawingpanel.clear(); polygonOptions = new PolygonOptions(); } }
- activity_map.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" tools:context=".LoginActivity"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/flMapContainer" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/map" class="com.googlemap.view.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/llMapActionContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:alpha="0" android:background="@drawable/input_roundedcorner" android:orientation="horizontal" android:visibility="gone"> <TextView android:id="@+id/textRedoSearchHere" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:clickable="true" android:gravity="center_horizontal" android:onClick="onRedoSearchClick" android:padding="8dp" android:text="Redo Search" android:textSize="14sp" /> <LinearLayout android:layout_width="1dp" android:layout_height="match_parent" android:layout_marginBottom="8dp" android:layout_marginTop="8dp" android:background="@color/gray_e8"> </LinearLayout> <TextView android:id="@+id/textDrawOnMap" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:clickable="true" android:gravity="center_horizontal" android:onClick="onDrawOnMapClick" android:padding="8dp" android:text="Draw on Map" android:textSize="14sp" /> </LinearLayout> <ProgressBar android:id="@+id/progressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </FrameLayout> </FrameLayout> </LinearLayout> </android.support.design.widget.CoordinatorLayout>
- input_roundedcorner.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> <corners android:radius="8dp" /> <solid android:color="@android:color/white" /> </shape> </item> </selector>
And done!
However if you face any issue in this Google Map Overlay tutorial, you can contact our mo developers for help.
Want To Create An Android Application?
Validate your app idea and get a free quote.
This is a great way to provide interactive features in your location-based mobile application. You can add this feature for your users to allow them to search their desired place just by drawing gesture on the Google map. And in case you want to develop such location-based featured app, contact us to hire Android app developer for developing your startup idea.
Grab a free copy of Google map custom overlay function demo from Github.
You may also like,
- Google Map – Plot a Current Location Pin on Google Map with Search Address functionality
- Integrating Google Map Marker to Show Lots of Data Using Android view
This page was last edited on December 28th, 2020, at 9:27.