LoginSignup
0
0

More than 5 years have passed since last update.

Android Custom Info Window for GoogleMaps Marker responsive to touch events

Posted at

When the user clicks on a marker, an info window is expected. Here, we demonstrate how to add a custom info window (a subclass of UIView) which responds to user touch events.

First, we must create the CustomCalloutView, a container which can hold any content. Regardless of the contents, we must add a tap gesture recognizer so that this callout can respond to touch events.

class CustomInfoWindowView: UIView {
    convenience init() {
        let tap = UITapGestureRecognizer(target: self, action: #selector(onTap))
        tap.numberOfTapsRequired = 1
        self.addGestureRecognizer(tap)
    }

    @objc func onTap() {}
}

We must also create a structure that links a marker with its associated custom info window.
When a custom info window is showing, we should maintain a reference to this structure so that future updates to its position can be performed.

struct SelectedInfoWindow {

    var marker: GMSMarker? = nil
    var infoWindow: UIView? = nil

    init(infoWindow: UIView, marker: GMSMarker) {
        self.infoWindow = infoWindow
        self.marker = marker
    }
}

When the user taps a marker, we add the CustomCalloutView as a subview of the mapView, making sure to generate the reference structure above after removing past info windows.

We also immediately set the position of the info window by calling self.updateInfoWindowPosition() as described below. This function must return "true" to ensure that the default info window does not appear.

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    self.removeInfoWindow()
    self.mapView?.subviews.filter{ $0 is CustomInfoWindowView }.forEach{
        $0.removeFromSuperview()
    }

    let infoWindow = CustomInfoWindowView()
    self.selectedInfoWindow = SelectedInfoWindow(infoWindow: infoWindow, marker: marker)
    self.mapView?.addSubview(infoWindow)
    self.updateInfoWindowPosition()

    return true
}

Here, an info window is removed and the reference structure deleted.

func removeInfoWindow() {
    guard
        let window = self.selectedInfoWindow?.infoWindow,
        let marker = self.selectedInfoWindow?.marker
        else {
        return
    }

    infoWindow.removeFromSuperview()
    self.selectedInfoWindow = nil
}

The central position of the info window is set relative to the center point of its associated marker, using mapView?.projection.point(for:). It is recommended to offset these centers so that the marker is not covered by the info window; this offset is therefore calculated from the size of the marker icon and custom infoWindow.

We should also call this function if the CustomCalloutView layout changes (i.e. override layoutSubViews to catch this event), because the infoWindow offset may have changed.

public func updateInfoWindowPosition() {

    guard
        let infoWindow = self.selectedInfoWindow?.infoWindow,
        let marker = self.selectedInfoWindow?.marker,
        let center = self.mapView?.projection.point(for: marker.position)
        else { return }

    window.center = center

    let markerHeight = marker.icon?.size.height ?? 0.0
    let infoWindowHeight = infoWindow.frame.height
    var offset: CGFloat = -0.5 * infoWindowHeight - markerHeight

    infoWindow.frame = window.frame.offsetBy(dx: 0.0, dy: offset)
}

When the map position changes, we must continue to update the infoWindow position.

func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
    self.updateInfoWindowPosition()
}

Finally, when the user deselects the marker by pressing the map at a location other than a marker, we must call the method to remove the info window.

func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
    self.removeInfoWindow()
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0