24
24
import com .google .android .gms .maps .model .LatLng ;
25
25
import com .google .android .gms .maps .model .MarkerOptions ;
26
26
27
- import android .content .Context ;
28
27
import android .os .Bundle ;
29
- import android .support .v4 .app .ListFragment ;
30
28
import android .support .v7 .app .AppCompatActivity ;
29
+ import android .support .v7 .widget .GridLayoutManager ;
30
+ import android .support .v7 .widget .LinearLayoutManager ;
31
+ import android .support .v7 .widget .RecyclerView ;
32
+ import android .view .LayoutInflater ;
33
+ import android .view .Menu ;
34
+ import android .view .MenuItem ;
31
35
import android .view .View ;
32
36
import android .view .ViewGroup ;
33
- import android .widget .AbsListView ;
34
- import android .widget .ArrayAdapter ;
35
37
import android .widget .TextView ;
36
38
37
- import java .util .HashSet ;
38
-
39
39
/**
40
40
* This shows to include a map in lite mode in a ListView.
41
41
* Note the use of the view holder pattern with the
42
42
* {@link com.google.android.gms.maps.OnMapReadyCallback}.
43
43
*/
44
44
public class LiteListDemoActivity extends AppCompatActivity {
45
45
46
- private ListFragment mList ;
46
+ private RecyclerView mRecyclerView ;
47
47
48
- private MapAdapter mAdapter ;
48
+ private LinearLayoutManager mLinearLayoutManager ;
49
+ private GridLayoutManager mGridLayoutManager ;
49
50
50
51
@ Override
51
52
protected void onCreate (Bundle savedInstanceState ) {
52
53
super .onCreate (savedInstanceState );
53
-
54
54
setContentView (R .layout .lite_list_demo );
55
55
56
- // Set a custom list adapter for a list of locations
57
- mAdapter = new MapAdapter (this , LIST_LOCATIONS );
58
- mList = (ListFragment ) getSupportFragmentManager ().findFragmentById (R .id .list );
59
- mList .setListAdapter (mAdapter );
56
+ mGridLayoutManager = new GridLayoutManager (this , 2 );
57
+ mLinearLayoutManager = new LinearLayoutManager (this );
60
58
61
- // Set a RecyclerListener to clean up MapView from ListView
62
- AbsListView lv = mList .getListView ();
63
- lv .setRecyclerListener (mRecycleListener );
59
+ // Set up the RecyclerView
60
+ mRecyclerView = findViewById (R .id .recycler_view );
61
+ mRecyclerView .setHasFixedSize (true );
62
+ mRecyclerView .setLayoutManager (mLinearLayoutManager );
63
+ mRecyclerView .setAdapter (new MapAdapter (LIST_LOCATIONS ));
64
+ mRecyclerView .setRecyclerListener (mRecycleListener );
65
+ }
64
66
67
+ /** Create a menu to switch between Linear and Grid LayoutManager. */
68
+ @ Override
69
+ public boolean onCreateOptionsMenu (Menu menu ) {
70
+ getMenuInflater ().inflate (R .menu .lite_list_menu , menu );
71
+ return true ;
72
+ }
73
+
74
+ @ Override
75
+ public boolean onOptionsItemSelected (MenuItem item ) {
76
+ switch (item .getItemId ()) {
77
+ case R .id .layout_linear :
78
+ mRecyclerView .setLayoutManager (mLinearLayoutManager );
79
+ break ;
80
+ case R .id .layout_grid :
81
+ mRecyclerView .setLayoutManager (mGridLayoutManager );
82
+ break ;
83
+ }
84
+ return true ;
65
85
}
66
86
67
87
/**
68
88
* Adapter that displays a title and {@link com.google.android.gms.maps.MapView} for each item.
69
89
* The layout is defined in <code>lite_list_demo_row.xml</code>. It contains a MapView
70
90
* that is programatically initialised in
71
- * {@link #getView (int, android.view.View, android.view.ViewGroup)}
91
+ * {@link #(int, android.view.View, android.view.ViewGroup)}
72
92
*/
73
- private class MapAdapter extends ArrayAdapter < NamedLocation > {
93
+ private class MapAdapter extends RecyclerView . Adapter < MapAdapter . ViewHolder > {
74
94
75
- private final HashSet < MapView > mMaps = new HashSet < MapView >() ;
95
+ private NamedLocation [] namedLocations ;
76
96
77
- public MapAdapter (Context context , NamedLocation [] locations ) {
78
- super (context , R .layout .lite_list_demo_row , R .id .lite_listrow_text , locations );
97
+ private MapAdapter (NamedLocation [] locations ) {
98
+ super ();
99
+ namedLocations = locations ;
79
100
}
80
101
81
-
82
102
@ Override
83
- public View getView (int position , View convertView , ViewGroup parent ) {
84
- View row = convertView ;
85
- ViewHolder holder ;
86
-
87
- // Check if a view can be reused, otherwise inflate a layout and set up the view holder
88
- if (row == null ) {
89
- // Inflate view from layout file
90
- row = getLayoutInflater ().inflate (R .layout .lite_list_demo_row , null );
91
-
92
- // Set up holder and assign it to the View
93
- holder = new ViewHolder ();
94
- holder .mapView = (MapView ) row .findViewById (R .id .lite_listrow_map );
95
- holder .title = (TextView ) row .findViewById (R .id .lite_listrow_text );
96
- // Set holder as tag for row for more efficient access.
97
- row .setTag (holder );
98
-
99
- // Initialise the MapView
100
- holder .initializeMapView ();
101
-
102
- // Keep track of MapView
103
- mMaps .add (holder .mapView );
104
- } else {
105
- // View has already been initialised, get its holder
106
- holder = (ViewHolder ) row .getTag ();
107
- }
108
-
109
- // Get the NamedLocation for this item and attach it to the MapView
110
- NamedLocation item = getItem (position );
111
- holder .mapView .setTag (item );
112
-
113
- // Ensure the map has been initialised by the on map ready callback in ViewHolder.
114
- // If it is not ready yet, it will be initialised with the NamedLocation set as its tag
115
- // when the callback is received.
116
- if (holder .map != null ) {
117
- // The map is already ready to be used
118
- setMapLocation (holder .map , item );
119
- }
120
-
121
- // Set the text label for this item
122
- holder .title .setText (item .name );
123
-
124
- return row ;
103
+ public ViewHolder onCreateViewHolder (ViewGroup parent , int viewType ) {
104
+ return new ViewHolder (LayoutInflater .from (parent .getContext ())
105
+ .inflate (R .layout .lite_list_demo_row , parent , false ));
125
106
}
126
107
127
108
/**
128
- * Retuns the set of all initialised {@link MapView} objects.
129
- *
130
- * @return All MapViews that have been initialised programmatically by this adapter
109
+ * This function is called when the user scrolls through the screen and a new item needs
110
+ * to be shown. So we will need to bind the holder with the details of the next item.
131
111
*/
132
- public HashSet <MapView > getMaps () {
133
- return mMaps ;
112
+ @ Override
113
+ public void onBindViewHolder (ViewHolder holder , int position ) {
114
+ if (holder == null ) {
115
+ return ;
116
+ }
117
+ holder .bindView (position );
134
118
}
135
- }
136
119
137
- /**
138
- * Displays a {@link LiteListDemoActivity.NamedLocation} on a
139
- * {@link com.google.android.gms.maps.GoogleMap}.
140
- * Adds a marker and centers the camera on the NamedLocation with the normal map type.
141
- */
142
- private static void setMapLocation (GoogleMap map , NamedLocation data ) {
143
- // Add a marker for this item and set the camera
144
- map .moveCamera (CameraUpdateFactory .newLatLngZoom (data .location , 13f ));
145
- map .addMarker (new MarkerOptions ().position (data .location ));
120
+ @ Override
121
+ public int getItemCount () {
122
+ return namedLocations .length ;
123
+ }
146
124
147
- // Set the map type back to normal.
148
- map .setMapType (GoogleMap .MAP_TYPE_NORMAL );
149
- }
125
+ /**
126
+ * Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}.
127
+ * Once the the <code>map</code> field is set, otherwise it is null.
128
+ * When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and
129
+ * the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map}
130
+ * field. The map is then initialised with the NamedLocation that is stored as the tag of the
131
+ * MapView. This ensures that the map is initialised with the latest data that it should
132
+ * display.
133
+ */
134
+ class ViewHolder extends RecyclerView .ViewHolder implements OnMapReadyCallback {
135
+
136
+ MapView mapView ;
137
+ TextView title ;
138
+ GoogleMap map ;
139
+ View layout ;
140
+
141
+ private ViewHolder (View itemView ) {
142
+ super (itemView );
143
+ layout = itemView ;
144
+ mapView = layout .findViewById (R .id .lite_listrow_map );
145
+ title = layout .findViewById (R .id .lite_listrow_text );
146
+ if (mapView != null ) {
147
+ // Initialise the MapView
148
+ mapView .onCreate (null );
149
+ // Set the map ready callback to receive the GoogleMap object
150
+ mapView .getMapAsync (this );
151
+ }
152
+ }
150
153
151
- /**
152
- * Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}.
153
- * Once the the <code>map</code> field is set, otherwise it is null.
154
- * When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and
155
- * the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map}
156
- * field. The map is then initialised with the NamedLocation that is stored as the tag of the
157
- * MapView. This ensures that the map is initialised with the latest data that it should
158
- * display.
159
- */
160
- class ViewHolder implements OnMapReadyCallback {
154
+ @ Override
155
+ public void onMapReady (GoogleMap googleMap ) {
156
+ MapsInitializer .initialize (getApplicationContext ());
157
+ map = googleMap ;
158
+ setMapLocation ();
159
+ }
161
160
162
- MapView mapView ;
161
+ /**
162
+ * Displays a {@link LiteListDemoActivity.NamedLocation} on a
163
+ * {@link com.google.android.gms.maps.GoogleMap}.
164
+ * Adds a marker and centers the camera on the NamedLocation with the normal map type.
165
+ */
166
+ private void setMapLocation () {
167
+ if (map == null ) return ;
163
168
164
- TextView title ;
169
+ NamedLocation data = (NamedLocation ) mapView .getTag ();
170
+ if (data == null ) return ;
165
171
166
- GoogleMap map ;
172
+ // Add a marker for this item and set the camera
173
+ map .moveCamera (CameraUpdateFactory .newLatLngZoom (data .location , 13f ));
174
+ map .addMarker (new MarkerOptions ().position (data .location ));
167
175
168
- @ Override
169
- public void onMapReady (GoogleMap googleMap ) {
170
- MapsInitializer .initialize (getApplicationContext ());
171
- map = googleMap ;
172
- NamedLocation data = (NamedLocation ) mapView .getTag ();
173
- if (data != null ) {
174
- setMapLocation (map , data );
176
+ // Set the map type back to normal.
177
+ map .setMapType (GoogleMap .MAP_TYPE_NORMAL );
175
178
}
176
- }
177
179
178
- /**
179
- * Initialises the MapView by calling its lifecycle methods.
180
- */
181
- public void initializeMapView () {
182
- if ( mapView != null ) {
183
- // Initialise the MapView
184
- mapView .onCreate ( null );
185
- // Set the map ready callback to receive the GoogleMap object
186
- mapView . getMapAsync ( this );
180
+ private void bindView ( int pos ) {
181
+ NamedLocation item = namedLocations [ pos ];
182
+ // Store a reference of the ViewHolder object in the layout.
183
+ layout . setTag ( this );
184
+ // Store a reference to the item in the mapView's tag. We use it to get the
185
+ // coordinate of a location, when setting the map location.
186
+ mapView .setTag ( item );
187
+ setMapLocation ();
188
+ title . setText ( item . name );
187
189
}
188
190
}
189
-
190
191
}
191
192
192
193
/**
193
194
* RecycleListener that completely clears the {@link com.google.android.gms.maps.GoogleMap}
194
- * attached to a row in the ListView .
195
+ * attached to a row in the RecyclerView .
195
196
* Sets the map type to {@link com.google.android.gms.maps.GoogleMap#MAP_TYPE_NONE} and clears
196
197
* the map.
197
198
*/
198
- private AbsListView .RecyclerListener mRecycleListener = new AbsListView .RecyclerListener () {
199
+ private RecyclerView .RecyclerListener mRecycleListener = new RecyclerView .RecyclerListener () {
199
200
200
201
@ Override
201
- public void onMovedToScrapHeap (View view ) {
202
- ViewHolder holder = (ViewHolder ) view .getTag ();
203
- if (holder != null && holder .map != null ) {
204
- // Clear the map and free up resources by changing the map type to none
205
- holder .map .clear ();
206
- holder .map .setMapType (GoogleMap .MAP_TYPE_NONE );
202
+ public void onViewRecycled (RecyclerView .ViewHolder holder ) {
203
+ MapAdapter .ViewHolder mapHolder = (MapAdapter .ViewHolder ) holder ;
204
+ if (mapHolder != null && mapHolder .map != null ) {
205
+ // Clear the map and free up resources by changing the map type to none.
206
+ // Also reset the map when it gets reattached to layout, so the previous map would
207
+ // not be displayed.
208
+ mapHolder .map .clear ();
209
+ mapHolder .map .setMapType (GoogleMap .MAP_TYPE_NONE );
207
210
}
208
-
209
211
}
210
212
};
211
213
@@ -216,7 +218,6 @@ public void onMovedToScrapHeap(View view) {
216
218
private static class NamedLocation {
217
219
218
220
public final String name ;
219
-
220
221
public final LatLng location ;
221
222
222
223
NamedLocation (String name , LatLng location ) {
0 commit comments