Map not clickable around marker in Google Map SDK for Android
Asked Answered
C

3

6

I am building some app like image below, I want to force markers not to be clickable, but there is no setClickable(false) for Marker or MarkerOptions. Currently area around marker (see attachment) is not clickable ( click is passed to marker, not map)

enter image description here

Charis answered 17/4, 2018 at 7:58 Comment(1)
It looks like this feature was requested in Google issue tracker: issuetracker.google.com/issues/35823783#comment13Bywaters
T
0

You have to use Overlay instead of marker in the Map to get exactly what you desire. You could follow this link, similar is done in JavaScript here.

Triumvirate answered 17/4, 2018 at 8:21 Comment(0)
K
0

I found a way to manually handle clicks for markers.

Add a touchable wrapper as described in this stackoverflow answer: https://mcmap.net/q/265637/-google-maps-android-api-v2-detect-touch-on-map

Add a gesture detector to your fragment and listen to single taps, then find the closest marker based on lat lng:

private var gestureDetector: GestureDetector? = null

...

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    gestureDetector = GestureDetector(context, GoogleMapsGestureListener { e -> onMapSingleTap(e) })

    //id of touchable wrapper - can use findViewById here instead if not using kotlin synthetics
    googleMapsTouchableWrapper?.onTouch = {
        gestureDetector?.onTouchEvent(it)
    }
}

private fun onMapSingleTap(e: MotionEvent) {
    val latLng = map?.projection?.fromScreenLocation(Point(e.x.toInt(), e.y.toInt())) ?: return

    //this assumes you are maintaining a set of the latlngs for your markers
    val closestNearbyLatLng = markerLatLngs?.findClosestNearbyLatLng(latLng)

    //assuming you have a map of latlng to marker you can now find that marker based on latlng and do whatever you need to with it

}

private fun Set<LatLng>.findClosestNearbyLatLng(latLng: LatLng): LatLng? {

    val map = map ?: return null

    val screenDistance = map.projection.visibleRegion.latLngBounds.northeast.distanceBetweenInKm(map.projection.visibleRegion.latLngBounds.southwest)

    val closestLatLng = this.minBy { latLng.distanceBetweenInKm(it) } ?: return null

    if (latLng.distanceBetweenInKm(closestLatLng) < screenDistance/40) {
        return closestLatLng
    }

    return null
}

fun LatLong.distanceBetweenInKm(latLng: LatLng): Double {

    if (this == latLng) {
        return 0.0
    }

    val earthRadius = 6371.0 //km value;

    //converting to radians
    val latPoint1Radians = Math.toRadians(latitude)
    val lngPoint1Radians = Math.toRadians(longitude)
    val latPoint2Radians = Math.toRadians(latLng.latitude)
    val lngPoint2Radians = Math.toRadians(latLng.longitude)

    var distance = sin((latPoint2Radians - latPoint1Radians) / 2.0).pow(2.0) + (cos(latPoint1Radians) * cos(latPoint2Radians)
            * sin((lngPoint2Radians - lngPoint1Radians) / 2.0).pow(2.0))
    distance = 2.0 * earthRadius * asin(sqrt(distance))

    return abs(distance) //km value
}

class GoogleMapsGestureListener(private val onSingleTap: (MotionEvent) -> Unit) : GestureDetector.SimpleOnGestureListener() {

    override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
        super.onSingleTapConfirmed(e)
        e?.let { onSingleTap(it) }
        return true
    }
}
Kinshasa answered 27/9, 2019 at 19:16 Comment(0)
E
0

I recently was able to create a formula to create an area surrounding a certain position on a Google Map, that is also scalable with zoom level.

Here I converted the LatLng coordinates from the marker to actual coordinates on the phone:

//array that holds all locations of every marker
//after a marker is created add the position in here
val positionList = mutableListOf<LatLng>()

//map is variable type GoogleMap
map.setOnMapClickListener {

  var inRange = false

  for(i in positionList.indices) {

  //establish corners of boundaries surrounding markers
  val points = positionList.toCoordinates(map)

  //check if clicked position falls in one of the positions' bounds
  val isInRangeLng = (points[i][2]..points[i][3]).contains(it.longitude)
  val isInRangeLat = (points[i][0]..points[i][1]).contains(it.latitude)

  //if click lands in of the positions' bounds, stop loop and return inRange 
  //true
  if(isInRangeLat && isInRangeLng) {
    inRange = true
    break
  }
}

  if(!inRange) {
    //APPLY YOUR LOGIC IF CLICK WAS NOT IN AREA
  } else {
    //APPLY YOUR LOGIC IF CLICK WAS IN AREA
  }
}
    
  //Extension function used to simplify logic
  /** Convert LatLng to coordinates on phone **/
  fun List<LatLng>.toCoordinates(map: GoogleMap): List<List<Double>> {
  val proj: Projection = map.projection

  val coordinateList = mutableListOf<List<Double>>()

  //create bounds for each position in list
  this.forEach {
  //get screen coordinates at the current LatLng
  val point = proj.toScreenLocation(it)
  val left = point.x - 100
  val right = point.x + 100
  val top = point.y - 100
  val bottom = point.y + 100

  //convert bounds into two points diagonal of each other
  val topRight = Point(right, top)
  val bottomLeft = Point(left, bottom)

  //convert the two points into LatLng points and get the bounds in north, 
  //south, west, and east
  val northEast = proj.fromScreenLocation(topRight)
  val north = northEast.latitude
  val east = northEast.longitude

  val southWest = proj.fromScreenLocation(bottomLeft)
  val south = southWest.latitude
  val west = southWest.longitude
    
  //add the bounds to be returned in a list which corresponds to a certain 
  //position
  coordinateList.add(listOf(
    south,
    north,
    west,
    east
  ))
 }

 return coordinateList
}

This can be used for a lot more than markers too.

Extracellular answered 27/1, 2022 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.