3

in iOS you can easily set a callout for your markers by calling:

[marker setCanShowCallout:YES];
[marker setRightCalloutAccessoryView:YOUR_BUTTON];

But I can't find this functionality for the Mapbox Android SDK. I do have a listener now which detects touches on the calloutview but how can i set a callout image / button?

Marker marker = new Marker(p.getTitle(), p.getCatagoryName(), new LatLng(p.getLatitude(), p.getLongitude()));
                        marker.setMarker(getResources().getDrawable(getResources().getIdentifier(string, "drawable", getActivity().getPackageName())));
                                mMapView.addMarker(marker);

                        InfoWindow toolTip = marker.getToolTip(mMapView);
                        View view = toolTip.getView();
                        // view.setBackgroundResource(R.drawable.callout_button); THIS DOES NOT WORK
                        view.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View view, MotionEvent motionEvent) {
                                Log.e(TAG, "onTouch");

                                return true;
                            }
                        });
Mark Molina
  • 5,057
  • 8
  • 41
  • 69
  • Hi Mark, did you ever figure this out? We've completed our iOS version with Mapbox and have started the Android version of our app. We're running into the same problem. We have an accessoryView on our iOS tooltip that leads the user to a "full screen view" of details relating to that point of interest. Repeating that functionality in Android though is quite undocumented ... unless we're missing something. – Joshua Powell Oct 08 '14 at 18:41
  • Sorry to say this but actually I didn't figure it out yet. I took a whole new look at my design and decided to implement the same method like google maps did. – Mark Molina Oct 09 '14 at 12:18
  • I think that's what we've been considering for the past couple days. After all, if you're using Google Maps on Android .. their design pattern doesn't use a tooltip/popup at all. They have a custom view that slides up from the bottom and is scrollable. We're thinking that might be a more natural approach on the Android platform. – Joshua Powell Oct 10 '14 at 13:08
  • Be warned though. The Android SDK doesn't include the google maps implementation. I had to create it from scratch. – Mark Molina Oct 10 '14 at 14:33

2 Answers2

5

You'll have to build this functionality yourself, but it's actually pretty easy to accomplish by defining a custom Marker and Tooltip Layout.

Start by defining your Tooltip layout. It has to be a RelativeLayout obviously to position the callout image. Set your context to whatever Activity is creating the markers. The TipView at the bottom must be included, because it controls sizing of the custom Tooltip.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@color/white"
    android:id="@+id/parent_layout"
    android:padding="5dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:context="com.XXX.MainActivity">

    <TextView
        android:id="@+id/tooltip_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="18sp"
        android:maxEms="17"
        android:layout_gravity="left"
        android:layout_weight="1"
        android:text="@string/toolTipTitle"/>

    <TextView
        android:id="@+id/tooltip_description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="14sp"
        android:maxEms="17"
        android:text="@string/toolTipDescription"
        android:layout_below="@+id/tooltip_title"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/marker_about"
        android:src="@drawable/ic_action_about"
        android:layout_toEndOf="@+id/tooltip_description"
        android:layout_toRightOf="@+id/tooltip_description"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="10dp" />

    <com.mapbox.mapboxsdk.views.TipView
            android:layout_width="132dp"
            android:layout_height="10dp"/>
</RelativeLayout>

Then create a custom Marker class and override the createTooltip method to return an InfoWindow with the new layout:

public class CustomMarker extends Marker {

    public CustomMarker(MapView mv, String aTitle, String aDescription, LatLng aLatLng){
        super(mv, aTitle, aDescription, aLatLng);
    }

    @Override
    protected InfoWindow createTooltip(MapView mv) {
        return new InfoWindow(R.layout.custom_tooltip, mv);
    }
}

This shouldn't change any other functionality, so the code you have will still work. Just change Marker to the custom class name and you should be set.

EDIT: Here's the code that actually sets the CustomMarker and InfoWindow up with my map. You can see that I'm launching another activity on click and that I've set a custom Icon for the marker, but that stuff isn't necessary:

        CustomMarker m =
                new CustomMarker(mv, report.issue, report.getFormattedDateString(), latLng);
        m.setIcon(new Icon(this, Icon.Size.LARGE, "oil-well", "FF0000"));
        //get the InfoWindow's view so that you can set a touch listener which will switch
        //to the marker's detailed view when clicked
        final InfoWindow infoWindow = m.getToolTip(mv);
        View view = infoWindow.getView();
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                //make sure to choose action down or up, otherwise the intent will launch twice
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                    startActivity(intent);
                    //close the InfoWindow so it's not still open when coming back to the map
                    infoWindow.close();
                }
                return true;
            }
        });
        mv.addMarker(m);

I'm also using SDK 0.5.0-SNAPSHOT. I'm not sure if this will work on older versions of the SDK.

Ryan Hamley
  • 1,989
  • 1
  • 15
  • 12
  • its makes a NullPointerException @ryansh – Nooh Nov 21 '14 at 04:22
  • Hey @Nooh I updated my response with the code that actually implements the marker and info window so you can check that out. Which version of the Mapbox SDK are you using? If you can give some more info on your problem, I can try to help. – Ryan Hamley Nov 26 '14 at 16:29
  • thanks @ryansh, Custom Marker Works fine, i got the result last week. – Nooh Nov 27 '14 at 05:27
  • awesome. glad it worked out @Nooh. apologies on the late reply. – Ryan Hamley Nov 28 '14 at 18:40
3

ryansh’s excellent response required that I include TextViews with ids tooltip_title and tooltip_description in the custom layout. I also had to add a third tooltip_subdescription TextView. The default InfoWindow code assumes these views exist and will crash if they don’t. For more control I extended InfoWindow, overrode onOpen and was able to use whatever layout I wanted for the tooltip. For the overridden createTooltip in the extended Marker class, I naturally instantiated and returned my extended InfoWindow object.

Update. Here is an example of extending the Marker & InfoWindow to support custom tooltip:

public class MapboxMarker extends Marker {
    private MyInfoWindow mInfoWindow;

    public class MyInfoWindow extends InfoWindow {

        public MyInfoWindow(int layoutResId, MapView mapView) {
            super(layoutResId, mapView);
        }

        public void onOpen(Marker overlayItem) {
            //
            //  Set data on mInfoWindow.getView()
            //
        }

    }

    public MapboxMarker(MapView mv, LatLng aLatLng, MapController mapController){
        super(mv, "Title", "Description", aLatLng);
    }

    @Override
    protected InfoWindow createTooltip(MapView mv) {
        mInfoWindow = new MyInfoWindow(R.layout.custom_tooltip_layout, mv);
        return mInfoWindow;
    }
}
AlanKley
  • 4,592
  • 8
  • 40
  • 53
  • I use your suggestion to override the InfoWindow but I got error said `There is no default constructor available`. How did you resolve that error in your case? Thank you. – Raditya Kurnianto Dec 17 '14 at 05:06
  • You add a default constructor to your derived class: public MyInfoWindow(int layoutResId, MapView mapView) { super(layoutResId, mapView); } – AlanKley Dec 17 '14 at 14:29
  • I also discovered that when I extended the Marker class and called the super constructor with empty values for title and description (super(mv, "", "", aLatLng) touching the markers stopped working. When I passed in non-empty strings (super(mv, " ", " ", aLatLng)), they started working again and calling MyMarker.onOpen – AlanKley Dec 17 '14 at 20:14
  • I did it, can you give the example of your when you try to implement completely custom layout to the info window? I try to do it but always got an error. @AlanKley – Raditya Kurnianto Dec 18 '14 at 13:46