Выбрать главу

Figure 34-1. Map with zoom indicator and compass rose

Center

Typically, you will need to control what the map is showing, beyond the zoom level, such as the user’s current location, or a location saved with some data in your activity. To change the map’s position, call setCenter() on the MapController.

This takes a GeoPoint as a parameter. A GeoPoint represents a location, via latitude and longitude. The catch is that the GeoPoint stores latitude and longitude as integers representing the actual latitude and longitude multiplied by 1E6. This saves a bit of memory versus storing a float or double, and it probably speeds up some internal calculations Android needs to do to convert the GeoPoint into a map position. However, it does mean you have to remember to multiply the “real world” latitude and longitude by 1E6.

Rugged Terrain

Just as the Google Maps you use on your full-size computer can display satellite imagery, so too can Android maps.

MapView offers toggleSatellite(), which, as the names suggest, toggles on and off the satellite perspective on the area being viewed. You can have the user trigger these via an options menu or, in the case of NooYawk, via keypresses:

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

 if (keyCode == KeyEvent.KEYCODE_S) {

  map.setSatellite(!map.isSatellite());

  return(true);

 } else if (keyCode == KeyEvent.KEYCODE_Z) {

  map.displayZoomControls(true);

  return(true);

 }

 return(super.onKeyDown(keyCode, event));

}

Layers Upon Layers

If you have ever used the full-size edition of Google Maps, you are probably used to seeing things overlaid atop the map itself, such as “push-pins” indicating businesses near the location being searched. In map parlance — and, for that matter, in many serious graphic editors — the push-pins are on a separate layer than the map itself, and what you are seeing is the composition of the push-pin layer atop the map layer.

Android’s mapping allows you to create layers as well, so you can mark up the maps as you need to based on user input and your application’s purpose. For example, NooYawk uses a layer to show where select buildings are located in the island of Manhattan.

Overlay Classes

Any overlay you want to add to your map needs to be implemented as a subclass of Overlay. There is an ItemizedOverlay subclass available if you are looking to add push-pins or the like; ItemizedOverlay simplifies this process.

To attach an overlay class to your map, just call getOverlays() on your MapView and add() your Overlay instance to it:

marker.setBounds(0, 0, marker.getIntrinsicWidth(),

 marker.getIntrinsicHeight());

map.getOverlays().add(new SitesOverlay(marker));

We will explain that marker in just a bit.

Drawing the ItemizedOverlay

As the name suggests, ItemizedOverlay allows you to supply a list of points of interest to be displayed on the map — specifically, instances of OverlayItem. The overlay, then, handles much of the drawing logic for you. Here are the minimum steps to make this work:

• First, override ItemizedOverlayOverlayItem as your own subclass (in this example, SitesOverlay)

• In the constructor, build your roster of OverlayItem instances, and call populate() when they are ready for use by the overlay

• Implement size() to return the number of items to be handled by the overlay

• Override createItem() to return OverlayItem instances given an index

• When you instantiate your ItemizedOverlay subclass, provide it with a Drawable that represents the default icon (e.g., push-pin) to display for each item

The marker from the NooYawk constructor is the Drawable used for the last bullet — it shows a push-pin, as illustrated in Figure 34-1 earlier in this chapter.

You may also wish to override draw() to do a better job of handling the shadow for your markers. While the map will handle casting a shadow for you, it appears you need to provide a bit of assistance for it to know where the “bottom” of your icon is, so it can draw the shadow appropriately.

For example, here is SitesOverlay:

private class SitesOverlay extends ItemizedOverlay<OverlayItem> {

 private List<OverlayItem> items = new ArrayList<OverlayItem>();

 private Drawable marker = null;

 public SitesOverlay(Drawable marker) {

  super(marker);

  this.marker = marker;

  items.add(new OverlayItem(getPoint(40.748963847316034,

   -73.96807193756104), "UN", "United Nations"));

  items.add(new OverlayItem(getPoint(40.76866299974387,

   -73.98268461227417), "Lincoln Center",

   "Home of Jazz at Lincoln Center"));

  items.add(new OverlayItem(getPoint(40.765136435316755,

   -73.97989511489868), "Carnegie Hall",

   "Where you go with practice, practice, practice"));

  items.add(new OverlayItem(getPoint(40.70686417491799,

   -74.01572942733765), "The Downtown Club",

   "Original home of the Heisman Trophy"));

  populate();

 }

 @Override

 protected OverlayItem createItem(int i) {

  return(items.get(i));

 }

 @Override

 public void draw(Canvas canvas, MapView mapView,

  boolean shadow) {