2

I am trying to implement a Google Map marker with infoWindow that if someone clicks on this infoWindow, it plays a song and if clicks again, it stops. To visualize this, I write a custom infoWindow layout. There is, in infoWindow, you can see user and track info with a button. This button shows play icon if the track does not begin to play yet, and if it pressed (press on infoWindow, not the button), I hope it changes its icon from "play" to "stop". However, I cannot change my custom infoWindow's view depending on infoWindowClickListener activity. I tried to change infoWindowAdapter especially but I do not want to change view of all other infoWindows and also I want to see the change immediately. In this way, the infoWindow refreshes its view after I click on the marker again. In other words, it does not change the view simultaneously with my click action.

Here you can see what I am talking about. Stop status on left, play status on right:

enter image description here

Here is my futile effort for adapter:

public class OrangeInfoWindowAdapter implements GoogleMap.InfoWindowAdapter {

    Context context;
    ImageButton playButton;
    boolean onPlay;

    public OrangeInfoWindowAdapter(Context context, boolean onPlay) {
        this.context = context;
        this.onPlay = onPlay;
    }

    @Override
    public View getInfoWindow(Marker arg0) {

        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(R.layout.orange_infowindow, null);

        v.setMinimumWidth(280);
        v.setMinimumHeight(120);

        TextView tvUsername = (TextView) v.findViewById(R.id.tv_username);
        TextView tvTrack = (TextView) v.findViewById(R.id.tv_track);

        int index = arg0.getTitle().indexOf("*");

        try {
            tvUsername.setText(arg0.getTitle().substring(0, index - 1) + "\n" + arg0.getTitle().substring(index + 2));
        } catch (StringIndexOutOfBoundsException e) {
        }

        tvUsername.setTextSize(10);
        tvUsername.setTextColor(Color.rgb(70, 70, 70));

        index = arg0.getSnippet().indexOf("*");

        try {
            tvTrack.setText(arg0.getSnippet().substring(0, index - 1) + "\n" + arg0.getSnippet().substring(index + 2));
        } catch (StringIndexOutOfBoundsException e) {
        }

        tvTrack.setTextSize(10);
        tvTrack.setTextColor(Color.rgb(230, 92, 1));

        playButton = (ImageButton) v.findViewById(R.id.playButton);

        if (onPlay)
            onPlay();

        return v;

    }

    public void onPlay() {
        playButton.setBackgroundResource(R.drawable.info_stop_button);
    }

    public void onStop() {
        playButton.setBackgroundResource(R.drawable.info_play_button);
    }

    @Override
    public View getInfoContents(Marker arg0) {
        return null;
    }
}

And this is my onInfoWindowClick():

@Override
public void onInfoWindowClick(Marker marker) {
    if (!infoWindowPlayerActive) {
        int index = findMarkerIndex(marker);
        OrangeInfoWindowAdapter infoWindowAdapter2 = new OrangeInfoWindowAdapter(getActivity().getApplicationContext(), true);
        googleMap.setInfoWindowAdapter(infoWindowAdapter2);
        new InfoWindowPlayerTask(mainActivity).execute(activities.get(index).getTrackId());
        infoWindowPlayerActive = true;
    }

    else {
        // same thing...
        infoWindowPlayerActive = false;
    }
}

If you want more information to understand the problem clearly, please ask me.

Dorukhan Arslan
  • 2,676
  • 2
  • 24
  • 42

2 Answers2

1

The GoogleMap API v.2 does not support any interaction on InfoWindow, besides opening and closing it.

However, there is an amazing hack implemented in this answer, on how you should create an interactive View inside your InfoWindow. Keep in mind that the same technique applies for Fragments too.

From the official documentation:

Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (e.g., after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.

Community
  • 1
  • 1
Menelaos Kotsollaris
  • 5,776
  • 9
  • 54
  • 68
  • I checked this before, seems really good. However, a touch wrapper for the map causes inflate error in ViewPager. After attaching new adapter, I tried to call "marker.showInfoWindow()" and it works. I know it is dirty solution but if it works, it is good in this condition. – Dorukhan Arslan May 03 '15 at 14:18
  • I have also implemented this hack on my application inside a `Fragment` and it works like a charm. Since the API does not support any native way, I think it's the only option to go. – Menelaos Kotsollaris May 03 '15 at 14:21
  • May I ask you something? It seems completely wrong for an unknown reason but I do not know exactly what makes calling "showInfoWindow()" after changing adapter so bad? Is there any performance problem caused by switching infoWindow frequently? – Dorukhan Arslan May 03 '15 at 15:25
  • I am using this technique and I have no lag issues. The lagg is almost the same with the lagg using the native InfoAdapter. Try to run it on a real device since the emulator GoogleMap is sometimes laggy. Everyone who has used this technique has given positive feedback too. – Menelaos Kotsollaris May 03 '15 at 15:57
  • I tried to update adapter. I assumed that was highly inefficient but still no lag. I will add my solution under the question. Check it if you have time. Thanks. – Dorukhan Arslan May 03 '15 at 16:19
0

I found a sloppy but working solution:

@Override
public void onInfoWindowClick(Marker marker) {
    if (!infoWindowPlayerActive) {
        googleMap.setInfoWindowAdapter(infoWindowAdapterOnPlay);
        marker.showInfoWindow();
        newClickedInfoWindowIndex = findMarkerIndex(marker);

        if (lastClickedInfoWindowIndex != newClickedInfoWindowIndex) {
            new InfoWindowPlayerTask(mainActivity).execute(activities.get(newClickedInfoWindowIndex).getTrackId());
        }
        else {
            mainActivity.getPlayerManager().clickPlayPause();
        }

        lastClickedInfoWindowIndex = newClickedInfoWindowIndex;
        infoWindowPlayerActive = true;
    }

    else {
        googleMap.setInfoWindowAdapter(infoWindowAdapter);
        marker.showInfoWindow();
        mainActivity.getPlayerManager().clickPlayPause();
        infoWindowPlayerActive = false;
    }
}

public int findMarkerIndex(Marker marker) {
    for (int i = 0; i < markers.size(); i++) {
        if (marker.getPosition().equals(markers.get(i).getPosition())) {
            return i;
        }
    }
    return -1;
}

Of course, assume that infoWindowPlayerActive, lastClickedInfoWindowIndex, newClickedInfoWindowIndex are defined in the class above.

Dorukhan Arslan
  • 2,676
  • 2
  • 24
  • 42