style personalizar multiple infowindows google custom close always all android google-maps google-maps-api-2 infowindow loadimage

android - personalizar - Añadir una imagen de url en InfoWindow google maps v2 personalizado



multiple infowindows google maps (4)

Cualquier cosa que devuelva de getInfoContents() , en ese momento, se convierte en un Bitmap y se utiliza para mostrar los resultados. No está mostrando la imagen hasta más tarde, cuando se completa la descarga, momento en el cual el Bitmap ya se ha creado y utilizado.

Deberá descargar la imagen antes de getInfoContents() .

Estoy trabajando en una aplicación de Android. El usuario realiza una búsqueda en google maps para restaurantes. En google map marcadores de visualización para todos los restaurantes de su vecino. Si toca un marcador, aparece una ventana de información personalizada. Mi problema es que no puedo cargar la imagen que devuelve el formulario de Google. Estoy acertando la url de la imagen pero no puedo mostrarla en la ventana.

Ventana de información

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:background="@color/bg_color" > <ImageView android:id="@+id/place_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false"" /> <TextView android:id="@+id/place_title" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/place_vicinity" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:background="@color/bg_color" > <RatingBar android:id="@+id/place_rating" style="?android:attr/ratingBarStyleSmall" android:numStars="5" android:rating="0" android:isIndicator="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dip" /> <ImageView android:id="@+id/navigate_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false" android:src="@drawable/navigate" /> </LinearLayout>

En crear tengo esto

mGoogleMap.setInfoWindowAdapter(new InfoWindowAdapter() { // Use default InfoWindow frame @Override public View getInfoWindow(Marker arg0) { return null; } // Defines the contents of the InfoWindow @Override public View getInfoContents(Marker arg0) { // Getting view from the layout file info_window_layout View v = getLayoutInflater().inflate(R.layout.info_window_layout, null); // Getting the snippet from the marker String snippet = arg0.getSnippet(); // Getting the snippet from the marker String titlestr = arg0.getTitle(); String cutchar1= "%#"; String cutchar2= "%##"; String ratingstr = snippet.substring(0,snippet.indexOf( cutchar1 )); String vicinitystr = snippet.substring(snippet.indexOf( cutchar1 )+2, snippet.indexOf( cutchar2 ) ); String iconurl= snippet.substring(snippet.indexOf( cutchar2 )+3); // Getting reference to the TextView to set latitude TextView title = (TextView) v.findViewById(R.id.place_title); TextView vicinity = (TextView) v.findViewById(R.id.place_vicinity); ImageView image = (ImageView) v.findViewById(R.id.navigate_icon); // Setting the latitude title.setText(titlestr); // declare RatingBar object RatingBar rating=(RatingBar) v.findViewById(R.id.place_rating);// create RatingBar object if( !(ratingstr.equals("null")) ){ rating.setRating(Float.parseFloat(ratingstr)); } vicinity.setText(vicinitystr); final DownloadImageTask download = new DownloadImageTask((ImageView) v.findViewById(R.id.place_icon) ,arg0); download.execute(iconurl); // Returning the view containing InfoWindow contents return v; }

});

y el código de DownloadImage es:

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { ImageView bmImage; Marker marker; boolean refresh; public DownloadImageTask(final ImageView bmImage, final Marker marker) { this.bmImage = bmImage; this.marker=marker; this.refresh=false; } public void SetRefresh(boolean refresh ){ this.refresh=true; } /* @Override protected void onPreExecute() { super.onPreExecute(); bmImage.setImageBitmap(null); }*/ @Override protected Bitmap doInBackground(String... urls) { String urldisplay = urls[0]; Bitmap mIcon11 = null; try { InputStream in = new java.net.URL(urldisplay).openStream(); mIcon11 = BitmapFactory.decodeStream(in); } catch (Exception e) { Log.e("Error", e.getMessage()); e.printStackTrace(); } return mIcon11; } @Override protected void onPostExecute(Bitmap result) { if(!refresh){ SetRefresh(refresh); bmImage.setImageBitmap(result); marker.showInfoWindow(); } } }

Finalmente, cuando ejecuto el código y toco el marcador, getInfoContents no detiene la ejecución y el icono no aparece.

¿Por qué sucede esto?


Hago esto, también haciendo referencia a la respuesta de @Daniel Gray :

if (userImg.getDrawable() == null) { Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl()) .error(R.drawable.logo) .into(userImg, new InfoWindowRefresher(marker)); } else { Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl()) .error(R.drawable.logo) .into(userImg); } public class InfoWindowRefresher implements Callback { private Marker markerToRefresh; public InfoWindowRefresher(Marker markerToRefresh) { this.markerToRefresh = markerToRefresh; } @Override public void onSuccess() { markerToRefresh.showInfoWindow(); } @Override public void onError() {} }


He estado construyendo una aplicación similar.

En primer lugar, la razón por la que su InfoWindow no muestra la imagen descargada es porque MapFragment convierte la vista en un Canvas y luego la dibuja. Lo que está viendo en la ventana de información no son las vistas que creó, sino una "imagen" o "captura de pantalla" de ellas. Básicamente, debes volver a llamar a showInfoWindow() en el objeto Marker , y eso volverá a representar el Canvas y tu imagen estará visible.

Sin embargo, dicho esto, en mi experiencia, cargar el Bitmap de Bitmap desde la URL y luego configurarlo no es la mejor solución. Android no maneja Bitmap s muy bien. Después de cargar varios mapas de bits, una excepción OutOfMemoryError es solo cuestión de tiempo, dependiendo de la cantidad de memoria del sistema que tenga.

Recomiendo usar la biblioteca de Picasso, que controla la descarga asíncrona y el almacenamiento en caché (en la memoria y el disco) y hace que la imagen real se cargue solo una línea ( Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView); ). (más información en http://square.github.io/picasso/ )

La respuesta anterior fue buena, excepto que, como él dijo, ese "retraso" es un poco demasiado mágico para mi gusto. Picasso tiene la opción de usar devoluciones de llamada, y yo recomendaría usar eso (lo estoy usando en mi aplicación).

Primero cree una clase (puede ser interna a su actividad) que implemente la interfaz de Callback de Callback de Picasso, y reciba un Marker en el constructor (para que pueda llamar a showInfoWindow() en ese marcador nuevamente.

private class InfoWindowRefresher implements Callback { private Marker markerToRefresh; private InfoWindowRefresher(Marker markerToRefresh) { this.markerToRefresh = markerToRefresh; } @Override public void onSuccess() { markerToRefresh.showInfoWindow(); } @Override public void onError() {} }

La ventana de información se ve así:

mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() { @Override public View getInfoWindow(Marker marker) { // inflate view window // set other views content // set image view like this: if (not_first_time_showing_info_window) { Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture); } else { // if it''s the first time, load the image with the callback set not_first_time_showing_info_window=true; Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture,new InfoWindowRefresher(marker)); } return v; } @Override public View getInfoContents(Marker marker) { return null; } });

La devolución de llamada es bastante simple, como se puede ver. Sin embargo, cuando use este método, DEBE tener cuidado de usar solo la devolución de llamada en la primera llamada, y no en las llamadas subsiguientes (solo puse esa not_first_time_showing_info_window para reflejar la idea ... tendrá que ver cómo incluirla en la lógica de tu programa. Si no lo haces, la devolución de llamada de Picasso llamará a showInfoWindow() y volverá a llamar a la devolución de llamada, lo que recordará a showInfoWindow() ... bueno, puedes ver a dónde va esa recursión. :)

Lo principal es conseguir que la carga de Picasso con la devolución de llamada se ejecute solo una vez, y en las llamadas posteriores, sin la devolución de llamada.


Resolví este problema usando magia negra (también conocida como configuración de un retraso). Aproveché el almacenamiento en caché de Picasso y llamé a showInfoWindow unos pocos milisegundos después de que la carga inicial hubiera comenzado.

Aquí está mi CustomWindowAdapter.

class CustomWindowAdapter implements InfoWindowAdapter{ LayoutInflater mInflater; Map<Marker, String> imageStringMapMarker; Context context; public CustomWindowAdapter(LayoutInflater i, Map<Marker, String> imageStringMapMarker2, Context context ){ mInflater = i; imageStringMapMarker = imageStringMapMarker2; } @Override public View getInfoContents(final Marker marker) { View v = mInflater.inflate(R.layout.custom_info_window, null); ImageView ivThumbnail = (ImageView) v.findViewById(R.id.ivThumbnail); String urlImage = imageStringMapMarker.get(marker).toString(); Picasso.with(context).load(Uri.parse(urlImage)).resize(250,250).into(ivThumbnail); return v; } @Override public View getInfoWindow(Marker marker) { // TODO Auto-generated method stub return null; } }

Y aquí está el método para llamar a la ventana de información en mi actividad principal donde implemento el retraso.

myMap.setInfoWindowAdapter(new CustomWindowAdapter(this.getLayoutInflater(), imageStringMapMarker, getApplicationContext())); myMap.setOnMarkerClickListener(new OnMarkerClickListener() { @Override public boolean onMarkerClick(final Marker mark) { mark.showInfoWindow(); final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { mark.showInfoWindow(); } }, 200); return true; } });