Search code examples
swiftgoogle-mapsgoogle-places-apiswift4gmsmapview

How to add tap event on GMSMarker without InfoView


I am beginner at Swift and a student.

I want to pop up detailed view when the GMSMarker is tapped. However when I tap GMSMarker, infoView will be called and then, infoView tapped, detailed view shows up on this code. How do I modify this? Isn't it possible to go straight to detailed view from GMSMarker without infoView?

//MARK: textfield
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    let autoCompleteController = GMSAutocompleteViewController()
    autoCompleteController.delegate = self
    
    let filter = GMSAutocompleteFilter()
    autoCompleteController.autocompleteFilter = filter
    
    self.locationManager.startUpdatingLocation()
    self.present(autoCompleteController, animated: true, completion: nil)
    return false
}

// MARK: GOOGLE AUTO COMPLETE DELEGATE
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
    let lat = place.coordinate.latitude
    let long = place.coordinate.longitude
    
    showPartyMarkers(lat: lat, long: long)
    
    let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 17.0)
    myMapView.camera = camera
    txtFieldSearch.text=place.formattedAddress
    chosenPlace = restaurant(name: place.formattedAddress!, lat: lat, long: long)
    let restaurantMarker=GMSMarker()
    restaurantMarker.position = CLLocationCoordinate2D(latitude: lat, longitude: long)
    restaurantMarker.title = "\(place.name)"
    restaurantMarker.snippet = "\(place.formattedAddress!)"
    restaurantMarker.map = myMapView
    
    self.dismiss(animated: true, completion: nil) // dismiss after place selected
}

func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
    print("ERROR AUTO COMPLETE \(error)")
}

func wasCancelled(_ viewController: GMSAutocompleteViewController) {
    self.dismiss(animated: true, completion: nil)
}

func initGoogleMaps() {
    let camera = GMSCameraPosition.camera(withLatitude: 28.7041, longitude: 77.1025, zoom: 17.0)
    self.myMapView.camera = camera
    self.myMapView.delegate = self
    self.myMapView.isMyLocationEnabled = true
}

// MARK: CLLocation Manager Delegate

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("Error while getting location \(error)")
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    locationManager.delegate = nil
    locationManager.stopUpdatingLocation()
    let location = locations.last
    let lat = (location?.coordinate.latitude)!
    let long = (location?.coordinate.longitude)!
    let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 17.0)
    
    self.myMapView.animate(to: camera)
    
    showPartyMarkers(lat: lat, long: long)
}

// MARK: GOOGLE MAP DELEGATE restaurantMarkerがタップされた時の動き
func mapView(_ mapView: GMSMapView, didTap restaurantMarker: GMSMarker) -> Bool {
    guard let customMarkerView = restaurantMarker.iconView as? CustomMarkerView else { return false }
    let img = customMarkerView.img!
    let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), image: img, borderColor: UIColor.white, tag: customMarkerView.tag)
    
    restaurantMarker.iconView = customMarker
    
    return false
}

func mapView(_ mapView: GMSMapView, markerInfoContents restaurantMarker: GMSMarker) -> UIView? {
    guard let customMarkerView = restaurantMarker.iconView as? CustomMarkerView else { return nil }
    let data = previewDemoData[customMarkerView.tag]
    restaurantPreviewView.setData(title: data.title, img: data.img, price: data.price)
    return restaurantPreviewView
}

func mapView(_ mapView: GMSMapView, didTapInfoWindowOf restaurantMarker: GMSMarker) {
    guard let customMarkerView = restaurantMarker.iconView as? CustomMarkerView else { return }
    let tag = customMarkerView.tag
    restaurantTapped(tag: tag)
}

func mapView(_ mapView: GMSMapView, didCloseInfoWindowOf restaurantMarker: GMSMarker) {
    guard let customMarkerView = restaurantMarker.iconView as? CustomMarkerView else { return }
    let img = customMarkerView.img!
    let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), image: img, borderColor: UIColor.darkGray, tag: customMarkerView.tag)
    restaurantMarker.iconView = customMarker
}
//マーカーがどう動くか
func showPartyMarkers(lat: Double, long: Double) {
    myMapView.clear()
    
    for restaurant in restaurants {
        let restaurantMarker=GMSMarker()
        let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), image: previewDemoData[0].img, borderColor: UIColor.darkGray, tag: 0)
        //[0]の部分をiにしてデータから順に引張てくるようにすれば良い
        restaurantMarker.position = CLLocationCoordinate2D(latitude: restaurant.lat, longitude: restaurant.long)
        restaurantMarker.iconView=customMarker
        restaurantMarker.map = self.myMapView
    }
}

@objc func btnMyLocationAction() {
    let location: CLLocation? = myMapView.myLocation
    if location != nil {
        myMapView.animate(toLocation: (location?.coordinate)!)
    }
}

@objc func restaurantTapped(tag: Int) {
    let v=DetailsVC()
    v.passedData = previewDemoData[tag]
    self.navigationController?.pushViewController(v, animated: true)
}

func setupTextField(textField: UITextField, img: UIImage){
    textField.leftViewMode = UITextFieldViewMode.always
    let imageView = UIImageView(frame: CGRect(x: 5, y: 5, width: 20, height: 20))
    imageView.image = img
    let paddingView = UIView(frame:CGRect(x: 0, y: 0, width: 30, height: 30))
    paddingView.addSubview(imageView)
    textField.leftView = paddingView
}

func setupViews() {
    view.addSubview(myMapView)
    myMapView.topAnchor.constraint(equalTo: view.topAnchor).isActive=true
    myMapView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive=true
    myMapView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive=true
    myMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 60).isActive=true
    
    self.view.addSubview(txtFieldSearch)
    txtFieldSearch.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive=true
    txtFieldSearch.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10).isActive=true
    txtFieldSearch.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10).isActive=true
    txtFieldSearch.heightAnchor.constraint(equalToConstant: 35).isActive=true
    setupTextField(textField: txtFieldSearch, img: #imageLiteral(resourceName: "map_Pin"))
    
    restaurantPreviewView=RestaurantPreviewView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 190))
    
    self.view.addSubview(btnMyLocation)
    btnMyLocation.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30).isActive=true
    btnMyLocation.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive=true
    btnMyLocation.widthAnchor.constraint(equalToConstant: 50).isActive=true
    btnMyLocation.heightAnchor.constraint(equalTo: btnMyLocation.widthAnchor).isActive=true
}

let myMapView: GMSMapView = {
    let v=GMSMapView()
    v.translatesAutoresizingMaskIntoConstraints=false
    return v
}()

let txtFieldSearch: UITextField = {
    let tf=UITextField()
    tf.borderStyle = .roundedRect
    tf.backgroundColor = .white
    tf.layer.borderColor = UIColor.darkGray.cgColor
    tf.placeholder="場所で検索"
    tf.translatesAutoresizingMaskIntoConstraints=false
    return tf
}()

let btnMyLocation: UIButton = {
    let btn=UIButton()
    btn.backgroundColor = UIColor.white
    btn.setImage(#imageLiteral(resourceName: "my_location"), for: .normal)
    btn.layer.cornerRadius = 5
    btn.clipsToBounds=true
    btn.tintColor = UIColor.white
    btn.imageView?.tintColor=UIColor.white
    btn.addTarget(self, action: #selector(btnMyLocationAction), for: .touchUpInside)
    btn.translatesAutoresizingMaskIntoConstraints=false
    return btn
}()

var restaurantPreviewView: RestaurantPreviewView = {
    let v=RestaurantPreviewView()
    return v
}()

Solution

  • Whenever a GMSMarker is tapped, you get the callback in GMSMapViewDelegate's method:

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

    By default, when a GMSMarker is tapped, infoWindow for that marker pops up. In case you want something else to happen on marker tap, add it to the delegate method and return true.

    func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool
    {
        //Your custom logic to move to another VC
        return true
    }