2010-06-02 15 views
9

Actualmente estoy tratando de colocar un MapView dentro de un ListView. ¿Ha tenido alguien algún éxito con esto? ¿Es posible? Aquí está mi código:Android - MapView contenida dentro de una Listview

  ListView myList = (ListView) findViewById(android.R.id.list); 
     List<Map<String, Object>> groupData = new ArrayList<Map<String, Object>>(); 

     Map<String, Object> curGroupMap = new HashMap<String, Object>(); 
     groupData.add(curGroupMap); 
     curGroupMap.put("ICON", R.drawable.back_icon); 
     curGroupMap.put("NAME","Go Back"); 
     curGroupMap.put("VALUE","By clicking here"); 

     Iterator it = data.entrySet().iterator(); 
     while (it.hasNext()) 
     { 
      //Get the key name and value for it 
      Map.Entry pair = (Map.Entry)it.next(); 
      String keyName = (String) pair.getKey(); 
      String value = pair.getValue().toString(); 

      if (value != null) 
      { 
       //Add the parents -- aka main categories 
       curGroupMap = new HashMap<String, Object>(); 
       groupData.add(curGroupMap); 

       //Push the correct Icon 
       if (keyName.equalsIgnoreCase("Phone")) 
        curGroupMap.put("ICON", R.drawable.phone_icon); 
       else if (keyName.equalsIgnoreCase("Housing")) 
        curGroupMap.put("ICON", R.drawable.house_icon); 
       else if (keyName.equalsIgnoreCase("Website")) 
        curGroupMap.put("ICON", R.drawable.web_icon); 
       else if (keyName.equalsIgnoreCase("Area Snapshot")) 
        curGroupMap.put("ICON", R.drawable.camera_icon); 
       else if (keyName.equalsIgnoreCase("Overview")) 
        curGroupMap.put("ICON", R.drawable.overview_icon); 
       else if (keyName.equalsIgnoreCase("Location")) 
        curGroupMap.put("ICON", R.drawable.map_icon); 
       else 
        curGroupMap.put("ICON", R.drawable.icon); 

       //Pop on the Name and Value 
       curGroupMap.put("NAME", keyName); 
       curGroupMap.put("VALUE", value); 
      } 
     } 

     curGroupMap = new HashMap<String, Object>(); 
     groupData.add(curGroupMap); 
     curGroupMap.put("ICON", R.drawable.back_icon); 
     curGroupMap.put("NAME","Go Back"); 
     curGroupMap.put("VALUE","By clicking here"); 

     //Set up adapter 
     mAdapter = new SimpleAdapter(
       mContext, 
       groupData, 
       R.layout.exp_list_parent, 
       new String[] { "ICON", "NAME", "VALUE" }, 
       new int[] { R.id.photoAlbumImg, R.id.rowText1, R.id.rowText2 } 
     ); 

     myList.setAdapter(mAdapter); //Bind the adapter to the list 

Gracias de antemano por su ayuda !!

+2

Ok, voy a morder. ¿Por qué necesita un MapView en un ListView? – CaseyB

+1

Además, ¿qué problemas estás experimentando? – CommonsWare

+0

Hipotético: enumera todo para un negocio específico. Me gustaría mostrar un mapa de dónde se encuentra en la lista. El problema que estoy experimentando es que no sé por dónde empezar. Me gustaría incluirlo dentro de un ListView en lugar de tener que iniciar un Intento nuevo (que de alguna manera derrota el propósito de la lista). – Ryan

Respuesta

5

En ese caso, agregaría MapView a la lista como lo haría con cualquier otra vista. Here's a quick tutorial sobre cómo crear un adaptador de lista personalizado. Pero tengo que advertirle, un MapView es una vista bastante pesada y si trata de obtener un montón de ellos en la pantalla, notará que la aplicación está lenta. Puede simplemente agregar un botón al elemento de la lista que lleva al usuario a otra página con más información, incluido un mapa.

+2

Creo que el enlace no es para mostrar mapview en un adaptador personalizado ... gentilmente, guíanme para tener un mapa en el listadapter –

+0

Tengo SupportMapFragment, ¿puedo usar dentro de la lista de la lista? Tengo un adaptador personalizado pero no entiendo cómo usar el mapa dentro de 'getChildView()' de 'BaseExpandableListAdapter'. Simplemente podemos hacer como '((TextView) convertView.findViewById (R.id.parent_txt_list_title)). SetText (parent.getTitle());' pero cómo podemos hacer lo mismo para el mapa. ¿Puedes ayudarme? –

+0

He agregado un mapa en una vista de lista pero enfrenta el problema de acercar/pellizcar. debido al desplazamiento de los padres. –

6

En primer lugar, no creo que mostrar múltiples MapViews a la vez funcione. MapActivity documenta que solo uno es compatible por proceso:

"Solo se admite una MapActivity por proceso. Es probable que varias MapActivities que se ejecutan simultáneamente interfieran de forma inesperada y no deseada".

(http://code.google.com/android/add-ons/google-apis/reference/index.html)

No explícitamente decir que no puede tener múltiples MapViews dentro de un MapActivity pero creo que van a interferir así, independientemente de qué clase de padre ViewGroup que se encuentran.

segundo lugar, usted podría considerar el uso de la API de mapas estáticos para obtener una imagen sencilla para su inclusión en el ListView - un MapView de pleno derecho puede ser innecesariamente peso pesado en todo caso:

http://code.google.com/apis/maps/documentation/staticmaps/

El único problema que puede enfrentar es que la API de Static Maps limita el uso por "usuario", lo que probablemente significa por IP (no requiere una clave API), y las redes móviles pueden ser problemáticas con limitaciones de uso de IP. No estoy seguro exactamente cómo se desarrollará.

+0

Hola Steve: no estoy tratando de mostrar vistas de mapas múltiples ... solo una. Además, el objetivo es que el usuario interactúe con el mapa, por lo que un mapa estático no funcionará desafortunadamente. Gracias por su sugerencia :) – Ryan

+0

Ah, ya veo. En ese caso, puede usar un adaptador de lista personalizado, como notó CaseyB, o quizás simplemente usar un LinearLayout vertical dentro de un ScrollView, si los elementos en su lista son en gran parte heterogéneos. – Steve

53

Para publicar una solución alternativa a una respuesta bastante antigua (en realidad más de 2 años), pero pensé que esto podría ayudar a alguien que podría tropezar con esta publicación como lo hice yo.

NOTA: Esto podría ser útil para alguien que simplemente necesita mostrar la ubicación en un "Mapa" pero no necesita interactuar con ella en el ListView. El mapa real se puede visualizar en digamos, un detalles página, después de hacer clic en un elemento de los ListView

Como ya se ha señalado por @CaseyB, MapView es una especie de vista pesado. Para contrarrestar ese aspecto (y hacer la vida un poco más fácil para mí ;-)), elegí construir una URL como lo haría para un Google Map estático, usando varios parámetros que son necesarios para mi aplicación. Puede obtener más opciones aquí: https://developers.google.com/maps/documentation/staticmaps/

primer lugar, cuando estoy construyendo los datos para mi ListView, paso de datos tales como el latitud y longitud a una cadena con algunas variables estáticas tomadas desde el enlace mencionado anteriormente . Obtengo mis coordenadas de la API de Facebook.

El código que utilizo para construir el enlace:

String getMapURL = "http://maps.googleapis.com/maps/api/staticmap?zoom=18&size=560x240&markers=size:mid|color:red|" 
+ JOLocation.getString("latitude") 
+ "," 
+ JOLocation.getString("longitude") 
+ "&sensor=false"; 

La URL se ha construido anteriormente, cuando se utiliza en un navegador, devuelve un archivo .PNG. Luego, en mi adapter para la actividad, utilizo @ Fedor's Lazy Loading para mostrar la imagen generada desde la URL que se construyó anteriormente para mostrarla en el ListView personalizado. Por supuesto, puede elegir su propio método para mostrar este Map (la imagen del mapa en realidad).

Un ejemplo del resultado final.

enter image description here

Actualmente, tengo unos 30 Mapas Checkin impares (lo uso en conjunción con el Facebook SDK) en este ListView, pero los usuarios pueden tener 100 es de ellos y no han sido absolutamente ningún informe de que la desaceleración abajo.

Sospecho que esto podría no ayudar al OP considerando el tiempo transcurrido desde la pregunta, pero espero que ayude a otros usuarios a aterrizar en esta página en el futuro.

+1

Excelente trabajo! – ChaturaM

+1

¡Guau, respuesta brillante! – tskulbru

+2

No se pudo pensar en una mejor manera. Gran trabajo. – Anirudh

-1

i se enfrentó al mismo problema hoy en día - resulta que usted tiene que crear el MapView dentro de su MapActivity lo contrario obtendrá un error como Incapaz de Inflar Ver com.google.maps.MapView más o menos .. Luego pasa este MapView a tu ListAdapter y escúpelo cuando sea necesario. Tuve que colocar el MapView dentro de un RelativeLayout para ajustar la altura y el ancho como quiera (por alguna razón, MapView no se comporta de la manera "normal"). Me puedes pedir detalles si te gusta :)

1

Es posible, desde el propio código GoogleMapSample:

/** 
* This shows to include a map in lite mode in a ListView. 
* Note the use of the view holder pattern with the 
* {@link com.google.android.gms.maps.OnMapReadyCallback}. 
*/ 
public class LiteListDemoActivity extends AppCompatActivity { 

    private ListFragment mList; 

    private MapAdapter mAdapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.lite_list_demo); 

     // Set a custom list adapter for a list of locations 
     mAdapter = new MapAdapter(this, LIST_LOCATIONS); 
     mList = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.list); 
     mList.setListAdapter(mAdapter); 

     // Set a RecyclerListener to clean up MapView from ListView 
     AbsListView lv = mList.getListView(); 
     lv.setRecyclerListener(mRecycleListener); 

    } 

    /** 
    * Adapter that displays a title and {@link com.google.android.gms.maps.MapView} for each item. 
    * The layout is defined in <code>lite_list_demo_row.xml</code>. It contains a MapView 
    * that is programatically initialised in 
    * {@link #getView(int, android.view.View, android.view.ViewGroup)} 
    */ 
    private class MapAdapter extends ArrayAdapter<NamedLocation> { 

     private final HashSet<MapView> mMaps = new HashSet<MapView>(); 

     public MapAdapter(Context context, NamedLocation[] locations) { 
      super(context, R.layout.lite_list_demo_row, R.id.lite_listrow_text, locations); 
     } 


     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
      View row = convertView; 
      ViewHolder holder; 

      // Check if a view can be reused, otherwise inflate a layout and set up the view holder 
      if (row == null) { 
       // Inflate view from layout file 
       row = getLayoutInflater().inflate(R.layout.lite_list_demo_row, null); 

       // Set up holder and assign it to the View 
       holder = new ViewHolder(); 
       holder.mapView = (MapView) row.findViewById(R.id.lite_listrow_map); 
       holder.title = (TextView) row.findViewById(R.id.lite_listrow_text); 
       // Set holder as tag for row for more efficient access. 
       row.setTag(holder); 

       // Initialise the MapView 
       holder.initializeMapView(); 

       // Keep track of MapView 
       mMaps.add(holder.mapView); 
      } else { 
       // View has already been initialised, get its holder 
       holder = (ViewHolder) row.getTag(); 
      } 

      // Get the NamedLocation for this item and attach it to the MapView 
      NamedLocation item = getItem(position); 
      holder.mapView.setTag(item); 

      // Ensure the map has been initialised by the on map ready callback in ViewHolder. 
      // If it is not ready yet, it will be initialised with the NamedLocation set as its tag 
      // when the callback is received. 
      if (holder.map != null) { 
       // The map is already ready to be used 
       setMapLocation(holder.map, item); 
      } 

      // Set the text label for this item 
      holder.title.setText(item.name); 

      return row; 
     } 

     /** 
     * Retuns the set of all initialised {@link MapView} objects. 
     * 
     * @return All MapViews that have been initialised programmatically by this adapter 
     */ 
     public HashSet<MapView> getMaps() { 
      return mMaps; 
     } 
    } 

    /** 
    * Displays a {@link LiteListDemoActivity.NamedLocation} on a 
    * {@link com.google.android.gms.maps.GoogleMap}. 
    * Adds a marker and centers the camera on the NamedLocation with the normal map type. 
    */ 
    private static void setMapLocation(GoogleMap map, NamedLocation data) { 
     // Add a marker for this item and set the camera 
     map.moveCamera(CameraUpdateFactory.newLatLngZoom(data.location, 13f)); 
     map.addMarker(new MarkerOptions().position(data.location)); 

     // Set the map type back to normal. 
     map.setMapType(GoogleMap.MAP_TYPE_NORMAL); 
    } 

    /** 
    * Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}. 
    * Once the the <code>map</code> field is set, otherwise it is null. 
    * When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and 
    * the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map} 
    * field. The map is then initialised with the NamedLocation that is stored as the tag of the 
    * MapView. This ensures that the map is initialised with the latest data that it should 
    * display. 
    */ 
    class ViewHolder implements OnMapReadyCallback { 

     MapView mapView; 

     TextView title; 

     GoogleMap map; 

     @Override 
     public void onMapReady(GoogleMap googleMap) { 
      MapsInitializer.initialize(getApplicationContext()); 
      map = googleMap; 
      NamedLocation data = (NamedLocation) mapView.getTag(); 
      if (data != null) { 
       setMapLocation(map, data); 
      } 
     } 

     /** 
     * Initialises the MapView by calling its lifecycle methods. 
     */ 
     public void initializeMapView() { 
      if (mapView != null) { 
       // Initialise the MapView 
       mapView.onCreate(null); 
       // Set the map ready callback to receive the GoogleMap object 
       mapView.getMapAsync(this); 
      } 
     } 

    } 

    /** 
    * RecycleListener that completely clears the {@link com.google.android.gms.maps.GoogleMap} 
    * attached to a row in the ListView. 
    * Sets the map type to {@link com.google.android.gms.maps.GoogleMap#MAP_TYPE_NONE} and clears 
    * the map. 
    */ 
    private AbsListView.RecyclerListener mRecycleListener = new AbsListView.RecyclerListener() { 

     @Override 
     public void onMovedToScrapHeap(View view) { 
      ViewHolder holder = (ViewHolder) view.getTag(); 
      if (holder != null && holder.map != null) { 
       // Clear the map and free up resources by changing the map type to none 
       holder.map.clear(); 
       holder.map.setMapType(GoogleMap.MAP_TYPE_NONE); 
      } 

     } 
    }; 

    /** 
    * Location represented by a position ({@link com.google.android.gms.maps.model.LatLng} and a 
    * name ({@link java.lang.String}). 
    */ 
    private static class NamedLocation { 

     public final String name; 

     public final LatLng location; 

     NamedLocation(String name, LatLng location) { 
      this.name = name; 
      this.location = location; 
     } 
    } 
} 

código completo está disponible en: https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java

+0

El enlace está inactivo actualizado https://github.com/googlemaps/android-samples/blob/master/ApiDemos/java/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java – Killer