304 lines
13 KiB
Plaintext
304 lines
13 KiB
Plaintext
|
page.title=Google Map View
|
||
|
parent.title=Hello, Views
|
||
|
parent.link=index.html
|
||
|
@jd:body
|
||
|
|
||
|
<p>Using the Google Maps library, you can create your own map-viewing Activity. In this
|
||
|
tutorial, you'll create a simple map application in two parts. In Part 1, you'll create an app that
|
||
|
shows a map the user can pan and zoom. In Part 2, you'll add overlay items that mark
|
||
|
points of interest.</p>
|
||
|
|
||
|
<div class="special">
|
||
|
<p>This tutorial requires that you have the external Google Maps library
|
||
|
installed in your SDK environment. The Maps library is included with the Google APIs
|
||
|
add-on, which you can install using the Android SDK and
|
||
|
AVD Manager. To learn how, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK
|
||
|
Components</a>.</p>
|
||
|
|
||
|
<p>After installing the Google APIs add-on in your SDK, set your project properties to use the build
|
||
|
target called "Google APIs by Google Inc.". See the instructions for setting a build
|
||
|
target in <a href="{@docRoot}guide/developing/eclipse-adt.html">Developing in
|
||
|
Eclipse with ADT</a> or <a
|
||
|
href="{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>,
|
||
|
as appropriate for your environment. </p>
|
||
|
|
||
|
<p>You will also need to set up a new AVD that uses the same Google APIs deployment target. See <a
|
||
|
href="{@docRoot}guide/developing/tools/avd.html">Android Virtual Devices</a> for
|
||
|
more information.</p>
|
||
|
|
||
|
<p>For reference material, see the <a
|
||
|
href="http://code.google.com/android/add-ons/google-apis/reference/index.html">Google Maps
|
||
|
library documentation</a>.</p>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<h2>Part 1: Creating a Map Activity</h2>
|
||
|
|
||
|
<ol>
|
||
|
<li>Start a new project named <em>HelloGoogleMaps</em>.</li>
|
||
|
|
||
|
<li>Because the Maps library is not a part of the standard Android library, you must
|
||
|
declare it in the Android Manifest. Open the <code>AndroidManifest.xml</code>
|
||
|
file and add the following as a child of the <code><application></code> element:
|
||
|
<pre><uses-library android:name="com.google.android.maps" /></pre>
|
||
|
</li>
|
||
|
|
||
|
<li>You also need access to the Internet in order to retrieve map tiles,
|
||
|
so you must also request the {@link android.Manifest.permission#INTERNET} permission.
|
||
|
In the manifest file, add the following as a child of the <code><manifest></code> element:
|
||
|
<pre><uses-permission android:name="android.permission.INTERNET" /></pre>
|
||
|
</li>
|
||
|
|
||
|
<li>While you're in the manifest, give the map some more space by getting rid of the title bar
|
||
|
with the "NoTitleBar" theme:
|
||
|
<pre>
|
||
|
<activity android:name=".HelloGoogleMaps" android:label="@string/app_name"
|
||
|
<strong>android:theme="@android:style/Theme.NoTitleBar"</strong>>
|
||
|
</pre>
|
||
|
</li>
|
||
|
|
||
|
|
||
|
<li>Open the <code>res/layout/main.xml</code> file and add a single
|
||
|
{@code com.google.android.maps.MapView} as the root node:
|
||
|
<pre>
|
||
|
<?xml version="1.0" encoding="utf-8"?>
|
||
|
<com.google.android.maps.MapView
|
||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||
|
android:id="@+id/mapview"
|
||
|
android:layout_width="fill_parent"
|
||
|
android:layout_height="fill_parent"
|
||
|
android:clickable="true"
|
||
|
android:apiKey="<em>Your Maps API Key goes here</em>"
|
||
|
/>
|
||
|
</pre>
|
||
|
<p>The <code>android:clickable</code> attribute defines whether you want to allow
|
||
|
user-interaction with the map. If this is "false" then touching the map does nothing.</p>
|
||
|
|
||
|
<p>The <code>android:apiKey</code> attribute holds the Maps API Key for your
|
||
|
application, which proves your application and signer certificate has been registered with the
|
||
|
Maps service. This is required in order to receive the map data, even while you are
|
||
|
developing. Registration to the service is free and it only takes a couple
|
||
|
minutes to register your certificate and get a Maps API Key.</p>
|
||
|
<p>Go now to get a key. For instructions, read
|
||
|
<a href="http://code.google.com/android/add-ons/google-apis/mapkey.html">Obtaining a Maps API
|
||
|
Key</a>. For the purpose of this tutorial, you should <a
|
||
|
href="http://code.google.com/android/add-ons/google-apis/mapkey.html#getdebugfingerprint">register
|
||
|
with the SDK debug certificate</a>, which will only be valid while your application is signed
|
||
|
with the debug key (once you sign with your private key, you will need a new API key).
|
||
|
When you get your key, insert it for the value of <code>android:apiKey</code>.</p>
|
||
|
</li>
|
||
|
|
||
|
<li>Now open the <code>HelloGoogleMaps.java</code> file. For this Activity, extend
|
||
|
{@code MapActivity} (instead of {@code android.app.Activity}):</p>
|
||
|
|
||
|
<pre>public class HelloGoogleMaps extends MapActivity {</pre>
|
||
|
<p>This is a special sub-class of {@link android.app.Activity}, provided by the Maps
|
||
|
library, which provides important map capabilities.</p>
|
||
|
|
||
|
<li>Inside every {@code MapActivity}, the <code>isRouteDisplayed()</code> method is required, so
|
||
|
override this method:
|
||
|
<pre>
|
||
|
@Override
|
||
|
protected boolean isRouteDisplayed() {
|
||
|
return false;
|
||
|
}
|
||
|
</pre>
|
||
|
<p>This method is required for some accounting from the Maps service to see if you're currently
|
||
|
displaying any route information. In this case, you're not, so return false.</p>
|
||
|
</li>
|
||
|
|
||
|
<li>Now add the standard {@link android.app.Activity#onCreate(Bundle) onCreate()} callback method
|
||
|
to the class:
|
||
|
<pre>
|
||
|
@Override
|
||
|
public void onCreate(Bundle savedInstanceState) {
|
||
|
super.onCreate(savedInstanceState);
|
||
|
setContentView(R.layout.main);
|
||
|
}
|
||
|
</pre>
|
||
|
<p>This loads the layout file created above. In fact, this is now a workable application that will
|
||
|
display map tiles and allow the user to pan around the map. But there's no ability to zoom.
|
||
|
Fortunately, there's a very simple zoom feature built into the {@code MapView} class, which you can
|
||
|
summon with {@code setBuiltInZoomControls(boolean)}. Do this at the end of the {@link
|
||
|
android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
|
||
|
<pre>
|
||
|
MapView mapView = (MapView) findViewById(R.id.mapview);
|
||
|
mapView.setBuiltInZoomControls(true);
|
||
|
</pre>
|
||
|
</li>
|
||
|
<li>That's all there is to it. Run the application. (Remember, you must have an <a
|
||
|
href="{@docRoot}guide/developing/tools/avd.html">AVD</a> configured to use the Google APIs
|
||
|
target, or be using a development device that includes the Maps library.)</li>
|
||
|
</ol>
|
||
|
|
||
|
<h2>Part 2: Adding Overlay Items</h2>
|
||
|
|
||
|
<p>So, now you have a map, but in many cases you'll also want to create your own map
|
||
|
markers and lay-overs. That's what you'll do now. In order to do so, you must implement the
|
||
|
{@code ItemizedOverlay} class, which can manage a whole set of {@code Overlay} (which are the
|
||
|
individual items placed on the map).</p>
|
||
|
|
||
|
<ol>
|
||
|
<li>Create a new Java class named <code>HelloItemizedOverlay</code> that implements
|
||
|
{@code ItemizedOverlay}.
|
||
|
|
||
|
<p>When using Eclipse, right-click the package name in the Eclipse Package Explorer, and
|
||
|
select <strong>New > Class</strong>. Fill-in
|
||
|
the Name field as <em>HelloItemizedOverlay</em>. For the Superclass, enter
|
||
|
"com.google.android.maps.ItemizedOverlay". Click the checkbox for <em>Constructors from
|
||
|
superclass</em>. Click Finish.</p></li>
|
||
|
|
||
|
<li>First, you need an <code>OverlayItem</code> {@link java.util.ArrayList}, in which you'll put
|
||
|
each of the <code>OverlayItem</code> objects you want on the map. Add this at the top of the
|
||
|
<code>HelloItemizedOverlay</code> class:
|
||
|
|
||
|
<pre>private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();</pre>
|
||
|
</li>
|
||
|
|
||
|
<li>Now define the <code>HelloItemizedOverlay</code> constructors. The constructor must
|
||
|
define the default marker for each of the {@code OverlayItem}s. In order for the {@link
|
||
|
android.graphics.drawable.Drawable} to actually get drawn, it must have its bounds defined. Most
|
||
|
commonly, you want the center-point at the bottom of the image to be the point at which it's
|
||
|
attached to the map coordinates. This is handled for you with the {@code boundCenterBottom()}
|
||
|
method. Wrap this around our defaultMarker, so the super constructor call looks like this:
|
||
|
<pre>
|
||
|
public HelloItemizedOverlay(Drawable defaultMarker) {
|
||
|
super(boundCenterBottom(defaultMarker));
|
||
|
}
|
||
|
</pre>
|
||
|
</li>
|
||
|
|
||
|
<li>In order to add new {@code OverlayItem}s to the ArrayList, you need a new method:
|
||
|
<pre>
|
||
|
public void addOverlay(OverlayItem overlay) {
|
||
|
mOverlays.add(overlay);
|
||
|
populate();
|
||
|
}</pre>
|
||
|
<p>Each time you add a new {@code OverlayItem} to the ArrayList, you must call
|
||
|
<code>populate()</code> for the {@code ItemizedOverlay}, which will read each of the
|
||
|
{@code OverlayItem}s and prepare them to be drawn.</p>
|
||
|
</li>
|
||
|
|
||
|
<li>When the <code>populate()</code> method executes, it will call <code>createItem(int)</code> in
|
||
|
the {@code ItemizedOverlay} to retrieve each {@code OverlayItem}. You must override this method to
|
||
|
properly read from the ArrayList and return the {@code OverlayItem} from the position specified
|
||
|
by the given integer. Your override method should look like this:
|
||
|
|
||
|
<pre>
|
||
|
@Override
|
||
|
protected OverlayItem createItem(int i) {
|
||
|
return mOverlays.get(i);
|
||
|
}
|
||
|
</pre>
|
||
|
</li>
|
||
|
|
||
|
<li>You must also override the <code>size()</code> method to return the current number of
|
||
|
items in the ArrayList:
|
||
|
<pre>
|
||
|
@Override
|
||
|
public int size() {
|
||
|
return mOverlays.size();
|
||
|
}
|
||
|
</pre>
|
||
|
</li>
|
||
|
|
||
|
<li>Now set up the ability to handle touch events on the overlay items. First, you're
|
||
|
going to need a reference to the application {@link android.content.Context} as a member of
|
||
|
this class. So add {@code Context mContext} as a class member, then initialize it with a
|
||
|
new class constructor:
|
||
|
<pre>
|
||
|
public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
|
||
|
super(defaultMarker);
|
||
|
mContext = context;
|
||
|
}
|
||
|
</pre>
|
||
|
<p>This passes the {@code defaultMarker} up to the default constructor to bound its coordinates
|
||
|
and then initialize {@code mContext} with the given {@link android.content.Context}.</p>
|
||
|
|
||
|
<p>Then override the {@code onTap(int)} callback method, which will handle the event
|
||
|
when an item is tapped by the user:</p>
|
||
|
<pre>
|
||
|
@Override
|
||
|
protected boolean onTap(int index) {
|
||
|
OverlayItem item = mOverlays.get(index);
|
||
|
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
|
||
|
dialog.setTitle(item.getTitle());
|
||
|
dialog.setMessage(item.getSnippet());
|
||
|
dialog.show();
|
||
|
return true;
|
||
|
}
|
||
|
</pre>
|
||
|
<p>This uses the member {@code android.content.Context} to create a new {@link
|
||
|
android.app.AlertDialog.Builder} and uses the tapped {@code OverlayItem}'s title and snippet for
|
||
|
the dialog's title and message text. (You'll see the {@code OverlayItem} title and snippet defined
|
||
|
when you create it below.)</p>
|
||
|
</li>
|
||
|
|
||
|
</ol>
|
||
|
|
||
|
<p>You're now done with the <code>HelloItemizedOverlay</code> class and can start using it
|
||
|
to add items on the map.</p>
|
||
|
|
||
|
<p>Go back to the <code>HelloGoogleMaps</code> class. In the following procedure, you'll create an
|
||
|
{@code OverlayItem} and add it to an instance of the <code>HelloItemizedOverlay</code> class, then
|
||
|
add the <code>HelloItemizedOverlay</code> to the <code>MapView</code> using a {@code GeoPoint}
|
||
|
to define its coordinates on the map.</p>
|
||
|
|
||
|
<img src="images/androidmarker.png" align="right" />
|
||
|
<ol>
|
||
|
<li>First, you need the image for the map overlay. If you don't have one handy, use the Android on
|
||
|
the right. Drag this image (or your own) into the <code>res/drawable/</code> directory of your
|
||
|
project.</li>
|
||
|
|
||
|
<li>At the end of your existing {@code onCreate()} method, instantiate :
|
||
|
|
||
|
<pre>
|
||
|
List<Overlay> mapOverlays = mapView.getOverlays();
|
||
|
Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
|
||
|
HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable);</pre>
|
||
|
|
||
|
<p>All overlay elements on a map are held by the {@code MapView}, so when you want to add some,
|
||
|
you have to get a list from the <code>getOverlays()</code> method. Then instantiate the {@link
|
||
|
android.graphics.drawable.Drawable} used for the map marker, which was saved in the {@code
|
||
|
res/drawable/} directory. The constructor for {@code HelloItemizedOverlay} (your custom {@code
|
||
|
ItemizedOverlay}) takes the Drawable in order to set the default marker for all overlay
|
||
|
items.</p>
|
||
|
</li>
|
||
|
|
||
|
<li>Now create a {@code GeoPoint} that defines the map coordinates for the first overlay item,
|
||
|
and pass it to a new {@code OverlayItem}:
|
||
|
<pre>
|
||
|
GeoPoint point = new GeoPoint(19240000,-99120000);
|
||
|
OverlayItem overlayitem = new OverlayItem(point, "Hola, Mundo!", "I'm in Mexico City!");
|
||
|
</pre>
|
||
|
|
||
|
<p>{@code GeoPoint} coordinates are specified in microdegrees (<code>degrees * 1e6</code>). The
|
||
|
{@code OverlayItem} constructor accepts the {@code GeoPoint} location, a string for the
|
||
|
item's title, and a string for the item's snippet text, respectively.</p>
|
||
|
</li>
|
||
|
|
||
|
<li>All that's left is to add this {@code OverlayItem} to your collection in the
|
||
|
{@code HelloItemizedOverlay} instance, then add the {@code HelloItemizedOverlay} to the MapView:
|
||
|
<pre>
|
||
|
itemizedoverlay.addOverlay(overlayitem);
|
||
|
mapOverlays.add(itemizedoverlay);
|
||
|
</pre>
|
||
|
</li>
|
||
|
|
||
|
<li>Now run the application.</li>
|
||
|
</ol>
|
||
|
|
||
|
<p>You should see the following:</p>
|
||
|
<img src="images/hello-mapview.png" width="150px" />
|
||
|
<p>When you tap the overlay item, you'll see the dialog appear.</p>
|
||
|
|
||
|
<p>Because the {@code ItemizedOverlay} class uses an {@code java.util.ArrayList} for all of the
|
||
|
{@code OverlayItem}s, it's easy to add more. Try adding another one. Before the
|
||
|
<code>addOverlay()</code> method is called, add these lines:</p>
|
||
|
<pre>
|
||
|
GeoPoint point2 = new GeoPoint(35410000, 139460000);
|
||
|
OverlayItem overlayitem2 = new OverlayItem(point2, "Sekai, konichiwa!", "I'm in Japan!");
|
||
|
</pre>
|
||
|
<p>Run the application again. (You probably need to move the map to find the new overlay item.)</p>
|
||
|
|