1

I am working on the google map project for navigation. and creating and displaying many polygons.

But when I try to click near the marker it always detects the marker point. So I would like to know that is there any property there where I can set the marker clickable radius?

I show that is available in the JavaScript but I could not find any lead regarding Android.

Any help or reference much appreciated.

Arpit Patel
  • 7,212
  • 5
  • 56
  • 67

1 Answers1

1

Anyway you can use a workaround:

  1. disable marker clicks response;

  2. detect touch on map determine nearest marker by yourself.

Of course, you need to store all of the markers in that case.

While the first point is simple:

mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
    @Override
    public boolean onMarkerClick(Marker marker) {
        return true;
    }
});

the second is not: even if "empty" onMarkerClick() return true markers will always intercept this event.

To get rid of that you can use approach with "touchable wrapper" like in this answer within custom MapFragment that can intercept touch events before they goes to MapFragment. When you get touch event you can get screen coordinates of touch. Then you need to find marker with minimal distance from touch location (you also need to convert marke's 'LatLng' position into screen flat coordinates via Projection.toScreenLocation() method). If founded marker within clickable radius you can process custom onMarkerClick event, if not - process polygon click.

Something like that:

Class TouchableWrapper - the core of approach:

public class TouchableWrapper extends FrameLayout {

    private static final int CLICK_RADIUS_IN_PIXELS = 25;

    private GoogleMap mGoogleMap;
    private List<Marker> mMarkers;

    public TouchableWrapper(Context context) {
        super(context);
    }

    public void setGoogleMapAndMarkers(GoogleMap googleMap, List<Marker> markers) {
        mGoogleMap = googleMap;
        mMarkers = markers;
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mGoogleMap == null) return super.dispatchTouchEvent(event);

        int screenX = (int) event.getX();
        int screenY = (int) event.getY();

        if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
            // find marker nearest to touch position
            Projection projection = mGoogleMap.getProjection();

            Marker nearestMarker = null;
            int minDistanceInPixels = Integer.MAX_VALUE;
            for (Marker marker : mMarkers) {
                Point markerScreen = projection.toScreenLocation(marker.getPosition());
                int distanceToMarker = (int) Math.sqrt((screenX - markerScreen.x) * (screenX - markerScreen.x)
                                                        + (screenY - markerScreen.y) * (screenY - markerScreen.y));
                if (distanceToMarker < minDistanceInPixels) {
                    minDistanceInPixels = distanceToMarker;
                    nearestMarker = marker;
                }
            }

            // "drop" nearest marker if it is not within radius
            if (minDistanceInPixels > CLICK_RADIUS_IN_PIXELS) {
                nearestMarker = null;
            }

            if (nearestMarker != null) {
                // decide what to process (marker click or polygon click) here
                Toast.makeText(getContext(),
                        "Clicked on marker " + nearestMarker.getTitle(), Toast.LENGTH_LONG).show();
            }
        }

        return super.dispatchTouchEvent(event);
    }
}

You can adjust clickable radius via CLICK_RADIUS_IN_PIXELS constant value.

Customized MapFragmet that uses TouchableWrapper class:

public class TouchableMapFragment extends MapFragment {
    public View originalContentView;
    public TouchableWrapper touchView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        originalContentView = super.onCreateView(inflater, parent, savedInstanceState);
        touchView = new TouchableWrapper(getActivity());
        touchView.addView(originalContentView);
        return touchView;
    }

    @Override
    public View getView() {
        return originalContentView;
    }
}

'MainActivity' that uses TouchableMapFragment:

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

    private static final String TAG = MainActivity.class.getSimpleName();

    static final LatLng MARKER_1 = new LatLng(50.450311, 30.523730);
    static final LatLng MARKER_2 = new LatLng(50.4502, 30.52365);

    private GoogleMap mGoogleMap;
    private TouchableMapFragment mMapFragment;
    private List<Marker> mMarkers = new ArrayList<>();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapFragment = (TouchableMapFragment) getFragmentManager()
                .findFragmentById(R.id.map_fragment);
        mMapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;

        // store markers
        Marker marker = mGoogleMap.addMarker(new MarkerOptions()
                .position(MARKER_1)
                .title("Marker 1"));
        mMarkers.add(marker);

        marker = mGoogleMap.addMarker(new MarkerOptions()
                .position(MARKER_2)
                .title("Marker 2"));
        mMarkers.add(marker);

        // pass stored markers to "touchable wrapper"
        mMapFragment.touchView.setGoogleMapAndMarkers(mGoogleMap, mMarkers);

        // disable marker click processing
        mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                return true;
            }
        });

        mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(MARKER_1, 14));
    }
}

and 'MainActivity' layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activities.MainActivity">

    <fragment
        android:id="@+id/map_fragment"
        android:name="<your.package.name>.TouchableMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

Also, in your case you need to pass List<Polygon> to TouchableWrapper like List<Marker> in example above and process polygon click in its dispatchTouchEvent(MotionEvent event) too.

Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79