android tab with interacting map and list views
2011-06-16 08:16
916 查看
from:http://joshclemm.com/blog/?p=86
Last tutorial, we wrote a simple app that displays two interacting list views in a
So, our goal in this tutorial is to have a list of geo coordinates and when we click on an item in the list, our map view goes to that location.
First off, let's create an XML layout that contains a
Once we have a layout, we need to create our main Activity. While last tutorial our
Why is this? Using a MapView in Android must be in a
Let's create a class called
In the
Next, we want to extract our
Then, we want to extract our
Once we have our
The
The final step is to add our two views (
Now if you were to run this app now, you may notice strange behavior (might just be on my phone). You should see our two tabs starting with the list view tab. Instead you may see the
Now everything should look right and you should be able to click a coordinate on the list view, and the map view tab goes to that spot on the earth.
If you are having issues with seeing the Map, remember you need to use the Google-Apis instead of the standard Android apis, you need to generate a Maps API key, you need to add interest permissions to the manifest, and you need to make sure the uses-library line is inside your application tag in the manifest.
Here's my manifest for reference:
To see an activity with a map and list view in action, check out my Earthquake Alert! Android App
Here's the full Java source code:
Last tutorial, we wrote a simple app that displays two interacting list views in a
TabActivity. In this tutorial, we will up the ante and add a
MapViewas the content of one of the tabs. Why again are we using multiple views in an activity instead of using a separate activity for each tab content? Remember, we want our tabs to be able to easily interact with one another, and keeping them as views allows us to handle the logic and interaction within one activity.
So, our goal in this tutorial is to have a list of geo coordinates and when we click on an item in the list, our map view goes to that location.
First off, let's create an XML layout that contains a
TabHost,
TabWidget, a
ListView, and a
MapView.
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < TabHost xmlns:android = "http://schemas.android.com/apk/res/android" |
03 | android:id = "@android:id/tabhost" android:layout_width = "fill_parent" |
04 | android:layout_height = "fill_parent" > |
05 | < LinearLayout android:orientation = "vertical" |
06 | android:layout_width = "fill_parent" android:layout_height = "fill_parent" > |
07 | < TabWidget android:id = "@android:id/tabs" |
08 | android:layout_width = "fill_parent" android:layout_height = "wrap_content" /> |
09 | < FrameLayout android:id = "@android:id/tabcontent" |
10 | android:layout_width = "fill_parent" android:layout_height = "fill_parent" > |
11 | < LinearLayout android:orientation = "vertical" |
12 | android:layout_width = "fill_parent" android:layout_height = "fill_parent" |
13 | android:id = "@+id/main" > |
14 | < ListView android:id = "@+id/list" android:layout_width = "fill_parent" |
15 | android:layout_height = "0dip" android:layout_weight = "1" /> |
16 | < TextView android:id = "@+id/empty" android:layout_width = "wrap_content" |
17 | android:layout_height = "wrap_content" android:gravity = "center" |
18 | android:text = "Loading" /> |
19 | </ LinearLayout > |
20 | < RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
21 | android:id = "@+id/mainlayout" android:orientation = "vertical" |
22 | android:layout_width = "fill_parent" android:layout_height = "fill_parent" > |
23 | < com.google.android.maps.MapView |
24 | android:id = "@+id/mapview" android:layout_width = "fill_parent" |
25 | android:layout_height = "fill_parent" android:clickable = "true" |
26 | android:apiKey = "[your MAPS API KEY here]" /> |
27 | </ RelativeLayout > |
28 | </ FrameLayout > |
29 | </ LinearLayout > |
30 | </ TabHost > |
Activitywas of type
TabActivity, in this tutorial our
Activityhas to be of type
MapActivity.
Why is this? Using a MapView in Android must be in a
MapActivityclass, otherwise your app with throw an Exception (take a look at the activities source code if you're interested in more details). As a result of this, we will have to perform the functions of
TabActivityourselves in the
MapActivityclass (you'll see that below).
Let's create a class called
TabbedListMapActivityand have it extend
MapActivity.
In the
onCreate()method, we need to set the content to our XML layout, extract the
TabHostobject, and call
setup()on the
TabHost(we need to do this because our Activity is not a TabActivity).
1 | setContentView(R.layout.main); |
2 |
3 | tabHost = (TabHost) findViewById(android.R.id.tabhost); |
4 |
5 | // setup must be called if you are not inflating the tabhost from XML |
6 | tabHost.setup(); |
ListViewfrom the XML, set it to a member variable, and add some initial coordinates to its list adapter.
1 | // setup list view |
2 | listView = (ListView) findViewById(R.id.list); |
3 | listView.setEmptyView((TextView) findViewById(R.id.empty)); |
4 |
5 | // create some dummy coordinates to add to the list |
6 | List<GeoPoint> pointsList = new ArrayList<GeoPoint>(); |
7 | pointsList.add( new GeoPoint(( int )( 32.864 *1E6), ( int )(- 117.2353 *1E6))); |
8 | pointsList.add( new GeoPoint(( int )( 37.441 *1E6), ( int )(- 122.1419 *1E6))); |
9 | listView.setAdapter( new ArrayAdapter( this , android.R.layout.simple_list_item_1, pointsList)); |
MapViewfrom the XML and set it to a member variable.
1 | // setup map view |
2 | mapView = (MapView) findViewById(R.id.mapview); |
3 | mapView.setBuiltInZoomControls( true ); |
4 | mapView.postInvalidate(); |
MapView, we can add a listener to the
ListViewfor selection events. Let's add a listener that when an item is clicked, we set the map to the coordinates of the selected item.
01 | // add an onclicklistener to see point on the map |
02 | listView.setOnItemClickListener( new OnItemClickListener() { |
03 | public void onItemClick(AdapterView parent, View view, int position, long id) { |
04 | GeoPoint geoPoint = (GeoPoint) listView.getAdapter().getItem(position); |
05 | if (geoPoint != null ) { |
06 | // have map view moved to this point |
07 | setMapZoomPoint(geoPoint, 12 ); |
08 | // programmatically switch tabs to the map view |
09 | tabHost.setCurrentTab( 1 ); |
10 | } |
11 | } |
12 | }); |
setMapZoomPointmethod is implemented like this:
1 | private void setMapZoomPoint(GeoPoint geoPoint, int zoomLevel) { |
2 | mapView.getController().setCenter(geoPoint); |
3 | mapView.getController().setZoom(zoomLevel); |
4 | mapView.postInvalidate(); |
5 | } |
MapViewand
ListView) as content to our tab host.
01 | // add views to tab host |
02 | tabHost.addTab(tabHost.newTabSpec( "List" ).setIndicator( "List" ).setContent( new TabContentFactory() { |
03 | public View createTabContent(String arg0) { |
04 | return listView; |
05 | } |
06 | })); |
07 | tabHost.addTab(tabHost.newTabSpec( "Map" ).setIndicator( "Map" ).setContent( new TabContentFactory() { |
08 | public View createTabContent(String arg0) { |
09 | return mapView; |
10 | } |
11 | })); |
MapView"bleeding" through the
ListView. I'm not exactly sure what causes this, but a workaround is to manually set the tab view to the map, then manually set the tab view back to the list. This causes the activity to redraw the tabs correctly. Here's my workaround in code:
1 | //HACK to get the list view to show up first, |
2 | // otherwise the mapview would be bleeding through and visible |
3 | tabHost.setCurrentTab( 1 ); //the mapview |
4 | tabHost.setCurrentTab( 0 ); //the listview |
If you are having issues with seeing the Map, remember you need to use the Google-Apis instead of the standard Android apis, you need to generate a Maps API key, you need to add interest permissions to the manifest, and you need to make sure the uses-library line is inside your application tag in the manifest.
Here's my manifest for reference:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < manifest xmlns:android = "http://schemas.android.com/apk/res/android" |
03 | package = "com.joshclemm.android.tutorial" android:versionCode = "1" |
04 | android:versionName = "1.0" > |
05 | < application android:icon = "@drawable/icon" android:label = "@string/app_name" > |
06 | < activity android:name = ".TabbedListMapActivity" android:label = "@string/app_name" > |
07 | < intent-filter > |
08 | < action android:name = "android.intent.action.MAIN" /> |
09 | < category android:name = "android.intent.category.LAUNCHER" /> |
10 | </ intent-filter > |
11 | </ activity > |
12 | < uses-library android:name = "com.google.android.maps" /> |
13 | </ application > |
14 | < uses-sdk android:minSdkVersion = "4" ></ uses-sdk > |
15 | < uses-permission android:name = "android.permission.INTERNET" /> |
16 | </ manifest > |
Here's the full Java source code:
001 | package com.joshclemm.android.tutorial; |
002 |
003 | import java.util.ArrayList; |
004 | import java.util.List; |
005 |
006 | import android.os.Bundle; |
007 | import android.view.View; |
008 | import android.widget.AdapterView; |
009 | import android.widget.ArrayAdapter; |
010 | import android.widget.ListView; |
011 | import android.widget.TabHost; |
012 | import android.widget.TextView; |
013 | import android.widget.AdapterView.OnItemClickListener; |
014 | import android.widget.TabHost.OnTabChangeListener; |
015 | import android.widget.TabHost.TabContentFactory; |
016 |
017 | import com.google.android.maps.GeoPoint; |
018 | import com.google.android.maps.MapActivity; |
019 | import com.google.android.maps.MapView; |
020 |
021 | public class TabbedListMapActivity extends MapActivity implements OnTabChangeListener { |
022 |
023 | private static final String LIST_TAB_TAG = "List" ; |
024 | private static final String MAP_TAB_TAG = "Map" ; |
025 |
026 | private TabHost tabHost; |
027 |
028 | private ListView listView; |
029 | private MapView mapView; |
030 |
031 | @Override |
032 | public void onCreate(Bundle savedInstanceState) { |
033 | super .onCreate(savedInstanceState); |
034 | setContentView(R.layout.main); |
035 |
036 | tabHost = (TabHost) findViewById(android.R.id.tabhost); |
037 |
038 | // setup must be called if you are not inflating the tabhost from XML |
039 | tabHost.setup(); |
040 | tabHost.setOnTabChangedListener( this ); |
041 |
042 | // setup list view |
043 | listView = (ListView) findViewById(R.id.list); |
044 | listView.setEmptyView((TextView) findViewById(R.id.empty)); |
045 |
046 | // create some dummy coordinates to add to the list |
047 | List<GeoPoint> pointsList = new ArrayList<GeoPoint>(); |
048 | pointsList.add( new GeoPoint(( int )( 32.864 *1E6), ( int )(- 117.2353 *1E6))); |
049 | pointsList.add( new GeoPoint(( int )( 37.441 *1E6), ( int )(- 122.1419 *1E6))); |
050 | listView.setAdapter( new ArrayAdapter( this , android.R.layout.simple_list_item_1, pointsList)); |
051 |
052 | // add an onclicklistener to see point on the map |
053 | listView.setOnItemClickListener( new OnItemClickListener() { |
054 | public void onItemClick(AdapterView parent, View view, int position, long id) { |
055 | GeoPoint geoPoint = (GeoPoint) listView.getAdapter().getItem(position); |
056 | if (geoPoint != null ) { |
057 | // have map view moved to this point |
058 | setMapZoomPoint(geoPoint, 12 ); |
059 | // programmatically switch tabs to the map view |
060 | tabHost.setCurrentTab( 1 ); |
061 | } |
062 | } |
063 | }); |
064 |
065 | // setup map view |
066 | mapView = (MapView) findViewById(R.id.mapview); |
067 | mapView.setBuiltInZoomControls( true ); |
068 | mapView.postInvalidate(); |
069 |
070 | // add views to tab host |
071 | tabHost.addTab(tabHost.newTabSpec(LIST_TAB_TAG).setIndicator( "List" ).setContent( new TabContentFactory() { |
072 | public View createTabContent(String arg0) { |
073 | return listView; |
074 | } |
075 | })); |
076 | tabHost.addTab(tabHost.newTabSpec(MAP_TAB_TAG).setIndicator( "Map" ).setContent( new TabContentFactory() { |
077 | public View createTabContent(String arg0) { |
078 | return mapView; |
079 | } |
080 | })); |
081 |
082 | //HACK to get the list view to show up first, |
083 | // otherwise the mapview would be bleeding through and visible |
084 | tabHost.setCurrentTab( 1 ); |
085 | tabHost.setCurrentTab( 0 ); |
086 | } |
087 |
088 | /** |
089 | * Instructs the map view to navigate to the point and zoom level specified. |
090 | * @param geoPoint |
091 | * @param zoomLevel |
092 | */ |
093 | private void setMapZoomPoint(GeoPoint geoPoint, int zoomLevel) { |
094 | mapView.getController().setCenter(geoPoint); |
095 | mapView.getController().setZoom(zoomLevel); |
096 | mapView.postInvalidate(); |
097 | } |
098 |
099 | /** |
100 | * From MapActivity, we ignore it for this demo |
101 | */ |
102 | @Override |
103 | protected boolean isRouteDisplayed() { |
104 | return false ; |
105 | } |
106 |
107 | /** |
108 | * Implement logic here when a tab is selected |
109 | */ |
110 | public void onTabChanged(String tabName) { |
111 | if (tabName.equals(MAP_TAB_TAG)) { |
112 | //do something on the map |
113 | } |
114 | else if (tabName.equals(LIST_TAB_TAG)) { |
115 | //do something on the list |
116 | } |
117 | } |
118 | } |
相关文章推荐
- Android ViewFlipper within TabHost for Tabs with different Views ... and better memory footprint
- android-Implementing Effective Navigation,Creating Swipe Views with Tabs
- android in practice_Managing a stateful list/Header and footer views
- Android官方文档学习之Creating Swipe Views with Tabs
- Android:Android ListActivity with a header or footer(为ListView添加header和footer)
- no lable views point to this text field with an android:lablFor=”@+id/@+id
- Programming Windows with MFC - Capter 10. Scroll Views, HTML Views, and Other View Types
- TabHost requires a TabWidget with id "android:id/tabs" 报错解决办法
- Something about set list and map in Java
- Android EditText with custom font and clear button
- [Android]Android NDK编译不识别list,map的问题
- Android overlay 学习 二 Android camera preview and take picture with V4l2
- Android tablayout and toolbar
- Android Studio using a library and project with the same package name
- Guava - List to Map and Multimap
- Android UI Testing with uiautomatorviewer and uiautomator
- [Ramda] Get a List of Unique Values From Nested Arrays with Ramda (flatMap --> Chain)
- 【Some】【WebSite】Fun with Android Shaders and Filters
- android 使用Tabhost 发生could not create tab content because could not find view with id 错...
- no lable views point to this text field with an android:lablFor=”@+id/@+id