Build Custom Info Windows in Android

In this blog post, we’ll go over how to build out custom Info Windows in Android.

What are Info Windows? In applications that display a list of locations in a map with pins, you can often tap on the pins to display information about that specific location. One example is the maps feature in the Yelp app where the app will display a map with various pins of locations of interest on the map. You can click on the pins and it’ll display a little pop up with the various data about that location. Sample screenshot is below.

That little pop up that displays with the label “El Gran Pollo”, rating table, and etc is the Info Window. The Android SDK comes with a standard InfoWindow that allows you to display a title and description. If that’s enough and the design of the standard InfoWindow meets your requirements, then you can stop here. If you need to customize your InfoWindow, continue reading.

Prerequisites

This tutorial is going to assume that you know how to integrate Google Maps into your Android application and that you know how to obtain location information using the LocationListener and GoogleApiClient.

Set those up first and prepare a list of data that you would like to display.

Sample data that we’ll be working with

We’ll be displaying different restaurants on the map. The model will look like

The name and description fields are straightforward. photoUrl field will return a url with an image file. We’ll be using Picasso to insert photos into the ImageView‘s.

Pin the markers

Assuming that your Google Map on your Activity (or Fragment) is set up and ready to go, we’ll start pinning the markers. We’ll have a list of Restaurants in an ArrayList and go from there.

The code above is simple but there are two non-obvious things. The first is the mRestaurantMap where we keep reference to the restaurants themselves with the markers as keys and the second is the last two lines of code where I call showInfoWindow and hideInfoWindow methods on the markers.

In the RestaurantInfoAdapter that we’ll be coding up next, we’ll need to be able to retrieve the correct restaurants that belong to a specific marker that the user taps on the screen. the mRestaurantMap HashMap is an easy way for us to store and retrieve the correct restaurants.

As for the showInfoWindow and hideInfoWindow methods, this is a workaround in order to display any images that you want to show on your Info Windows. As noted in the comments in the code snippet above, you do not need these two lines of code if you do not have any images in your custom info windows.

Write the InfoAdapter

Let’s write our Custom Info Adapter and the accompanying XML layout file.

First create your custom layout file. I’ll be naming the file info_window_restaurant. The code for the layout is below.

In this layout, I’m using a CardView in order to easily provide rounding border radius. If that’s not a requirement for you, then you can use whatever layout (RelativeLayout, LinearLayout, etc.) that you want. I also have an ImageView in there to display the photo of the restaurants that will come in later.

Next up, let’s build our Info Adapter. Back in your Activity or Fragment file where you had that pinMarker method, add this class.

Here, you can see the mRestaurantMap coming into play, where we take the marker that is passed in to retrieve the correct Restaurant from mRestaurantMap. Then we grab that and set the texts and images for the TextView‘s and the ImageView.

If you are observant, you may have noticed the new MarkerCallback(marker) line in the Picasso part of the getInfoWindow method. This is a workaround that we have to do specifically when trying to load images in custom info windows due to the race condition that occur between Picasso and Google Maps. This StackOverflow post’s accepted answer explains it pretty well.

https://stackoverflow.com/questions/39551774/picasso-image-not-loading-in-custom-infowindow-why/39551998#39551998

Basically, you’ll need to build a custom callback into Picasso or your image loading in your custom info windows will be inconsistent at best and non-functional at worst. Also, I found the code solution in that StackOverflow post to not work for me, so without further ado, below is the solution that have worked for me.

And yep, the solution is pretty much the same, except that I call hideInfoWindow before showInfoWindow. I found that just calling showInfoWindow doesn’t help reload the page.

Also, remember the two lines of code in the pinMarkers method where I call hideInfoWindow and showInfoWindow during the pin marking process? The reason I do that is because if I don’t, the image in the first pin that the user taps on, the image will never load. I’m not sure why, but hiding and showing the info windows quickly (so that the user doesn’t notice) when you’re pinning the markers initially is a workaround that I found to work well.

You can also further optimize this solution by adding a boolean variable in your RestaurantInfoAdapter to determine whether Picasso has already loaded and displayed the image or not. Since Picasso automatically caches images for you, if the marker has been tapped and image already loaded and displayed, we do not have to add the MarkerCallback into our Picasso calls. This is simple to do so I won’t display that here.

I hope this post helps anyone who needs to build custom info windows in their Android apps.

About the Author Chris Jeon

Software developer currently focusing on Android development.