Creating and Using Overlays

Overlays enable you to add annotations and click handling to MapViews. Each Overlay lets you draw 2D primitives, including text, lines, images, and shapes, directly onto a canvas, which is then overlaid onto a Map View.

You can add several Overlays onto a single map. All the Overlays assigned to a Map View are added as layers, with newer layers potentially obscuring older ones. User clicks are passed through the stack until they are either handled by an Overlay or registered as clicks on the Map View itself.

Creating New Overlays

Each Overlay is a canvas with a transparent background that is layered onto a Map View and used to handle map touch events.

To add a new Overlay create a new class that extends Overlay. Override the draw method to draw the annotations you want to add, and override onTap to react to user clicks (generally made when the user taps an annotation added by this Overlay).

Listing 8-8 shows the framework for creating a new Overlay that can draw annotations and handle user clicks.

LISTING 8-8: Creating a new Overlay

Available for import android.graphics.Canvas; download on

Wrox.com import com.google.android.maps.MapView;

import com.google.android.maps.Overlay;

public class MyOverlay extends Overlay { @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { if (shadow == false) {

@Override public boolean onTap(GeoPoint point, MapView mapView) {

// Return true if screen tap is handled by this overlay return false;

Introducing Projections

The canvas used to draw Overlay annotations is a standard Canvas that represents the visible display surface. To add annotations based on physical locations, you need to convert between geographical points and screen coordinates.

The Projection class lets you translate between latitude/longitude coordinates (stored as GeoPoints) and x/y screen pixel coordinates (stored as Points).

A map's Projection may change between subsequentcalls to draw, so it's good practice to get a new instance each time. Get a Map View's Projection by callinggetProjection.

Projection projection = mapView.getProjection();

Use the fromPixel and toPixel methods to translate from GeoPoints to Points and vice versa.

For performance reasons, you can best use the toPixel Projection method by passing a Point object to be populated (rather than relying on the return value), as shown in Listing 8-9.

LISTING 8-9: Using map projections Available for download on Point myPoint = new Point(); Wrox.com //To screen coordinates projection.toPixels(geoPoint, myPoint); //To GeoPoint location coordinates projection.fromPixels(myPoint.x, myPoint.y);

Drawing on the Overlay Canvas

You handle Canvas drawing for Overlays by overriding the Overlay'draw handler.

The passed-in Canvas is the surface on which you draw your annotations, using the same techniques introduced in Chapter 4 for creating custom user interfaces for Views. The Canvas object includes the methods for drawing 2D primitives on your map (including lines, text, shapes, ellipses, images, etc.). Use Paint objects to define the style and color.

Listing 8-10 uses a Projection to draw text and an ellipse at a given location.

LISTING 8-10: A simple Map Overlay

Available for

Wrox.com

©Override download on public void draw(Canvas canvas, MapView mapView, boolean shadow) {

Projection projection = mapView.getProjection(); Double lat = -31.960906*1E6;

continues

LISTING 8-10 (continued)

Double lng = 115.844822*1E6;

GeoPoint geoPoint = new GeoPoint(lat.intValue(), lng.intValue());

Point myPoint = new Point(); projection.toPixels(geoPoint, myPoint);

// Create and setup your paint brush Paint paint = new Paint(); paint.setARGB(250, 255, 0, 0); paint.setAntiAlias(true); paint.setFakeBoldText(true);

RectF oval = new RectF(myPoint.x-rad, myPoint.y-rad, myPoint.x+rad, myPoint.y+rad);

// Draw on the canvas canvas.drawOval(oval, paint);

canvas.drawText("Red Circle", myPoint.x+rad, myPoint.y, paint);

For more advanced drawing features see Chapter 11, where gradients, strokes, and filters are introduced.

Handling Map Tap Events

To handle map taps (user clicks), override the onTap event handler within the Overlay extension class. The onTap handler receives two parameters:

> A GeoPoint that contains the latitude/longitude of the map location tapped

> The MapView that was tapped to trigger this event

When you are overriding onTap, the method should return true if it has handled a particular tap and false to let another Overlay handle it, as shown in Listing 8-11.

LISTING 8-11: Handling map-tap events

Wrox.com public boolean onTap(GeoPoint point, MapView mapView) {

// Perform hit test to see if this overlay is handling the click if ([ ... perform hit test ... ]) {

[ ... execute on tap functionality ... ] return true;

// If not handled return false return false;

Adding and Removing Overlays

Each MapView contains a list of Overlays currently displayed. You can get a reference to this list by calling getOverlays, as shown in the following snippet:

List<Overlay> overlays = mapView.getOverlays();

Adding and removing items from the list is thread-safe and synchronized, so you can modify and query the list safely. You should still iterate over the list within a synchronization block synchronized on the List.

To add an Overlay onto a Map View, create a new instance of the Overlay and add it to the list, as shown in the following snippet.

List<Overlay> overlays = mapView.getOverlays(); MyOverlay myOverlay = new MyOverlay(); overlays.add(myOverlay); mapView.postInvalidate();

The added Overlay will be displayed the next time the Map View is redrawn, so it's usually a good practice to call postInvalidate after you modify the list to update the changes on the map display.

Annotating 'Where Am I?'

This final modification to''Where Am I?'' creates and adds a new Overlay that displays a white circle at the device's current position.

1. Start by creating a new MyPositionOverlay Overlay class in the Where Am I? project.

package com.paad.whereami;

import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.RectF; import android.location.Location; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection;

public class MyPositionOverlay extends Overlay {

@Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { }

@Override public boolean onTap(GeoPoint point, MapView mapView) {

Prepared for ASHLEE KABAT, email: [email protected] Order number: 56760408 This PDF is for the purchaser's personal use in accordance with the Wrox Terms of Service and under US copyright as stated on this book's copyright page. If you did not purchase this copy, please visit www.wrox.com to purchase your own copy.

return false;

2. Create a new instance variable to store the current Location, and add setter and getter methods for it.

Location location;

public Location getLocation() { return location;

public void setLocation(Location location) { this.location = location;

3. Override the draw method to add a small white circle at the current location. private final int mRadius = 5;

©Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { Projection projection = mapView.getProjection();

// Get the current location

Double latitude = location.getLatitude()*1E6; Double longitude = location.getLongitude()*1E6; GeoPoint geoPoint; geoPoint = new

GeoPoint(latitude.intValue(),longitude.intValue());

// Convert the location to screen pixels Point point = new Point(); projection.toPixels(geoPoint, point);

RectF oval = new RectF(point.x - mRadius, point.y - mRadius, point.x + mRadius, point.y + mRadius);

// Setup the paint

paint.setARGB(250, 255, 255, 255);

paint.setAntiAlias(true);

paint.setFakeBoldText(true);

Paint backPaint = new Paint(); backPaint.setARGB(175, 50, 50, 50); backPaint.setAntiAlias(true);

RectF backRect = new RectF(point.x + 2 + mRadius, point.y - 3*mRadius, point.x + 65, point.y + mRadius);

// Draw the marker canvas.drawOval(oval, paint);

canvas.drawRoundRect(backRect, 5, 5, backPaint); canvas.drawText("Here I Am", point.x + 2*mRadius, point.y, paint);

super.draw(canvas, mapView, shadow);

4. Now open the WhereAmI Activity class, and add the MyPositionOverlay to the MapView.

Start by adding a new instance variable to store the MyPositionOverlay, then override onCreate to create a new instance of the class, and add it to the MapView's Overlay list.

MyPositionOverlay positionOverlay; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

MapView myMapView = (MapView)findViewById(R.id.myMapView); mapController = myMapView.getController();

myMapView.setSatellite(true);

myMapView.setStreetView(true);

myMapView.displayZoomControls(false);

mapController.setZoom(17);

// Add the MyPositionOverlay positionOverlay = new MyPositionOverlay(); List<Overlay> overlays = myMapView.getOverlays(); overlays.add(positionOverlay);

LocationManager locationManager;

String context = Context.LOCATION_SERVICE;

locationManager = (LocationManager)getSystemService(context);

Criteria criteria = new Criteria();

criteria.setAccuracy(Criteria.ACCURACY_FINE);

criteria.setAltitudeRequired(false);

criteria.setBearingRequired(false);

criteria.setCostAllowed(true);

criteria.setPowerRequirement(Criteria.POWER_LOW);

String provider = locationManager.getBestProvider(criteria, true); Location location = locationManager.getLastKnownLocation(provider); updateWithNewLocation(location);

locationManager.requestLocationUpdates(provider, 2000, 10, locationListener);

5. Finally, update the updateWithNewLocation method to pass the new location to the Overlay.

private void updateWithNewLocation(Location location) { String latLongString; TextView myLocationText;

Prepared for ASHLEE KABAT, email: [email protected] Order number: 56760408 This PDF is for the purchaser's personal use in accordance with the Wrox Terms of Service and under US copyright as stated on this book's copyright page. If you did not purchase this copy, please visit www.wrox.com to purchase your own copy.

myLocationText = (TextView)findViewById(R.id.myLocationText); String addressString = "No address found";

// Update my location marker positionOverlay.setLocation(location);

// Update the map location. Double geoLat = location.getLatitude()*1E6; Double geoLng = location.getLongitude()*1E6; GeoPoint point = new GeoPoint(geoLat.intValue(), geoLng.intValue());

mapController.animateTo(point);

double lat = location.getLatitude(); double lng = location.getLongitude(); latLongString = "Lat:" + lat + "\nLong:" + lng;

double latitude = location.getLatitude(); double longitude = location.getLongitude();

Geocoder gc = new Geocoder(this, Locale.getDefault()); try {

List<Address> addresses = gc.getFromLocation(latitude, longitude, 1);

StringBuilder sb = new StringBuilder(); if (addresses.size() >0) {

Address address = addresses.get(0);

for (int i = 0; i < address.getMaxAddressLineIndex(); i++) sb.append(address.getAddressLine(i)).append("\n");

sb.append(address.getLocality()).append("\n");

sb.append(address.getPostalCode()).append("\n");

sb.append(address.getCountryName());

addressString = sb.toString(); } catch (IOException e) {} } else {

latLongString = "No location found";

myLocationText.setText("Your Current Position is:\n" +

latLongString + "\n" + addressString);

All code snippets in this example are part of the Chapter 8 Where Am I? project, available for download at Wrox.com.

When run, your application will display your current device location with a white circle and supporting text, as shown in Figure 8-6.

It's worth noting that this is not the preferred technique for displaying your current location on a map. This functionality is implemented natively by Android through the MyLocationOverlay class. If you want to display and follow your current location, you should consider using (or extending) this class, as shown in the next section, instead of implementing it manually as shown here.

Mobile Apps Made Easy

Mobile Apps Made Easy

Quick start guide to skyrocket your offline and online business success with mobile apps. If you know anything about mobile devices, you’ve probably heard that famous phrase coined by one of the mobile device’s most prolific creators proclaiming that there’s an app for pretty much everything.

Get My Free Training Guide


Responses

  • Flavia
    How to set image on map through using ontap() in overlay android?
    7 years ago

Post a comment