Swift - GoogleMaps SDK get coordinates on touch - swift

I am new to swift and the Google Maps SDK, and was wondering how to get the coordinates of where the user has tapped using the Google Maps SDK. For example if a user holds their finger down on a certain place on a map, a annotation is created there. I would really appreciate your help, thanks.

In the GMSMapViewDelegate there is a method named: mapView:didLongPressAtCoordinate: which is called after a long-press gesture at a particular coordinate. See the reference here.
By implementing this method you could then add a marker to the map view:
func mapView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
let marker = GMSMarker(position: coordinate)
marker.title = "Hello World"
marker.map = mapView
}
For a tap gesture a similar delegate method can be implemented called mapView:didTapAtCoordinate: which can be used in a similar way:
func mapView(mapView: GMSMapView!, didTapAtCoordinate coordinate: CLLocationCoordinate2D) {
print("Tapped at coordinate: " + String(coordinate.latitude) + " "
+ String(coordinate.longitude))
}

Try this
extension ViewController: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D)
{
print("Tapped at coordinate: " + String(coordinate.latitude) + " "
+ String(coordinate.longitude))
}
}

For Swift 5.0+
First, make sure you have added GMSMapViewDelegate delegate to your ViewController Class
Add this default function in your class
func mapView(_ mapView: GMSMapView, didLongPressAt coordinate: CLLocationCoordinate2D) {
debugPrint("Coordinates: ", coordinate)
}
If you just want coordinates, then above function is perfect for you But if you want to create Marker or get local address from touch then see below function
func mapView(_ mapView: GMSMapView, didLongPressAt coordinate: CLLocationCoordinate2D) {
let marker = GMSMarker(position: coordinate) //Add this line if you want to add marker
let decoder = CLGeocoder()
decoder.reverseGeocodeLocation(CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)) { placemarks, err in
if let placeMark = placemarks?.first {
let plName = placeMark.name ?? placeMark.subThoroughfare ?? placeMark.thoroughfare! //Place Name
var address : String! = "" //This will be the local address
if let subLocality = placeMark.subLocality ?? placeMark.name {
address.append(subLocality)
address.append(", ")
}
if let city = placeMark.locality ?? placeMark.subAdministrativeArea {
address.append(city)
address.append(", ")
}
if let state = placeMark.administrativeArea, let country = placeMark.country {
address.append(state)
address.append(", ")
address.append(country)
}
// Add Marker:
marker.title = plName
marker.snippet = address
marker.appearAnimation = .pop
marker.map = mapView
}
}
}
This Function does not only get coordinates but creates a Marker with all the details fetched from the coordinates(Like PlaceName, city, state,country etc.) too
If you just want local address, then remove all the code lines related to marker
The reason why i have used CLGeocoder and not GMSGeocoder from
GoogleMapDelegate is that Apple's CLGeocoder is much more precise
in getting the place-name while GMSGeocoder does not fetch
place-name accurately.
Also Note that : Apple's Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may
cause some of the requests to fail.

Related

Problem with callout button and firestore in swift

I have 5 collections on Firestore. With the data of the documents of those collections, I create annotations of different types and display them on a map view.
The problem is that I want to pass all the information that is stored in each annotation and display it on another view controller, that appears when you press the callout button.
I can't figure out a way of referencing the annotation I'm pressing and then pass the data to the other screen.
This is my first time using databases and I don't have many experience, so I would appreciate some help.
Thanks!
It's difficult to give a specific answer since I don't know the full scope of your features. But this is how you generally do it.
First when you create the MKAnnotation subclass, you define a property to hold an object that you can reference later. For example, say I'm showing restaurants and supermarkets in a map.
class RestaurantAnnotation: NSObject, MKAnnotation {
let restaurant: Restaurant
var title: String? {
return restaurant.name
}
var coordinate: CLLocationCoordinate2D {
return restaurant.coordinate
}
init(restaurant: Restaurant) {
self.restaurant = restaurant
super.init()
}
}
struct Restaurant {
let name: String
let coordinate: CLLocationCoordinate2D
}
Same goes for the supermarkets.
Then when you create the annotation, you pass the Restaurant object to it.
let restaurant = Restaurant(name: "McDonald's", coordinate: CLLocationCoordinate2D(latitude: 27.2831, longitude: -127.831))
let restaurantAnnotation = RestaurantAnnotation(restaurant: restaurant)
mapView.addAnnotation(restaurantAnnotation)
You implement the mapView(_:annotationView:calloutAccessoryControlTapped:) delegate method to be notified when the user taps on the callout button in annotations. In it, you can easily reference the object you passed to it earlier.
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if let annotation = view.annotation as? RestaurantAnnotation {
print(annotation.restaurant)
} else if let annotation = view.annotation as? SupermarketAnnotation {
print(annotation.supermarket)
}
}
And you can use that data to do whatever you want after that. In your case, pass it to a new screen.

How to open google maps when tapped any where on gmsmapview

I have a classified application. When posting an ad you need to give your location as a viewer i can see the marked location and map-view but the marked location only open in the google maps when i tap the google button on the bottom left corner of gmsmapview. I want the user to be enable to open the marked location in google maps when he taps anywhere in the map. Is there any function that detects tap anywhere on the map.
This code will check if google maps are installed. If yes it will open location in maps else will open the location in safari.
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
if(self.current_long != "" && self.current_lat != "")
{
//Add your latitude
let lat: String = self.current_lat
//Add your longitude
let lon: String = self.current_long
if (UIApplication.shared.canOpenURL(URL(string:"comgooglemaps://")!)) {
UIApplication.shared.open(URL(string:"comgooglemaps://?center=\(lat),\(lon)&zoom=14&views=traffic&q=\(lat),\(lon)")!, options: [:], completionHandler: nil)
}else{
print("Cannot open maps")
if let urlDestination = URL.init(string: "https://www.google.com/maps/?center=\(lat),\(lon)&zoom=14&views=traffic&q=\(lat),\(lon)"){
UIApplication.shared.open(urlDestination, options: [:], completionHandler: nil)
}
}
}
}

Assigning an accessibility identifier to an MKMapView object

I'm trying to configure snapshot for an app I'm working in, it already works in the english version but in the localized versions I don't know how to assign an accessibility identifier to a pin in the Map in MKMapView, somebody knows hows to do this?
Thanks.
Accessibility identifiers are a great way to separate your application's language from Xcode UI Testing. The identifier comes from UIAccessibilityIdentification which UIView already conforms to. However, neither NSObject nor MKAnnotation conform to the protocol. So you have to set that conformance yourself.
class Annotation: NSObject, MKAnnotation, UIAccessibilityIdentification {
let coordinate: CLLocationCoordinate2D
let title: String?
var accessibilityIdentifier: String?
init(title: String?, coordinate: CLLocationCoordinate2D) {
self.title = title
self.coordinate = coordinate
}
}
let coordinate = CLLocationCoordinate2DMake(40.703490, -73.987770)
let annotation = Annotation(title: "BeerMenus HQ", coordinate: coordinate)
annotation.accessibilityIdentifier = "Custom Identifier"
let mapView = MKMapView()
mapView.addAnnotation(annotation)
Then under test you can reference the annotation via otherElements.
let app = XCUIApplication()
let annotation = app.maps.element.otherElements["Custom Identifier"]
annotation.tap()

How can I find a user's location using Google Maps SDK for Swift?

So I am trying to get it so I open the app and it starts off at the user's location. The problem is I am getting "User's location is unknown" in the output box. I have location enabled as seen in the code below, so I am wondering if something else might be causing this issue. Help would be appreciated thanks.
import UIKit
import GoogleMaps
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let camera = GMSCameraPosition.cameraWithLatitude(-33.86,
longitude: 151.20, zoom: 6)
let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView.accessibilityElementsHidden = false
mapView.myLocationEnabled = true
self.view = mapView
if let mylocation = mapView.myLocation {
print("User's location: \(mylocation)")
} else {
print("User's location is unknown")
}
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(-33.86, 151.20)
marker.title = "Sydney"
marker.snippet = "Australia"
marker.map = mapView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Have you tried using CLLocationManager() ?
Try the tutorial below, this should show you how to get the user's location. This will take you through asking the user for permission to see their location, down to reverse geocoding the location to display the address they are at, using GMSGeocoder()
[https://www.raywenderlich.com/109888/google-maps-ios-sdk-tutorial][1]
[1]: Ray Wenderlich
Hope that helps
I tried this so:
Set a custom String for the authorization request when in use (or whatever you need) in "Privacy - Location When In Use Usage Description" (or simply NSLocationWhenInUseUsageDescription) of my Info.plist properties file. Then this will ask you authorize finding your location.
Set the properly delegate (GMSMapViewDelegate) in your view: for example
class MapView: UIViewController, GMSMapViewDelegate{...}
And finally set delegate to your GMSMapView instance. In my case mapView:
let mapView = GMSMapView.map(withFrame: frameMapViewContainer, camera: camera)
mapView.delegate = self

viewForAnnotation not being called (using Alamofire to parse JSON)

I'm new to iOS programming. I prefer to use Swift.
What I'm trying to do is call a web service that returns some JSON, parse the JSON into a custom object called Entry and plot those entries on a map.
I am using AlamoFire to make the web service call and SwiftyJSON to parse the JSON into Entry objects like below
request(.GET, URLString: "https://myURLThatReturnsJson")
.responseJSON { (_, _, json, error) in
if let json: AnyObject = json{
let jsonEntries = JSON(json)
for result in jsonEntries["entries"].arrayValue {
let business_name = result["business_name"].stringValue
let latitude = result["lat"].stringValue
let longitude = result["lng"].stringValue
let category = result["category"].stringValue
let address = result["address"].stringValue
let city = result["city"].stringValue
let type = result["type"].stringValue
let location = result["location"].stringValue
let valid = result["valid"].stringValue
let comments = result["comments"].stringValue
let date = result["date"].stringValue
let username = result["username"].stringValue
let additional_comment_count = result["additional_comment_count"].stringValue
let entry : Entry = Entry(
business_name: business_name,
latitude: latitude,
longitude: longitude,
category: category,
address: address,
city: city,
type: type,
location: location,
valid: valid,
comments: comments,
date: date,
username: username,
additional_comment_count: additional_comment_count,
title: business_name,
subtitle: location,
coordinate: CLLocationCoordinate2D(latitude: (latitude as NSString).doubleValue, longitude: (longitude as NSString).doubleValue))
entries.append(entry)
}
// Now we have our array of entries. Now plot them.
for entry in entries{
self.mapView.addAnnotation(entry)
}
}
}
So as you can see in the code above I am also mapping the entries within the AlamoFire request (don't know if this is bad because AlamoFire is done on a separate thread I believe).
I also have a viewForAnnotations method that looks like below
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
print("viewForAnnotation called")
return nil
}
My viewForAnnotation method is not being called at all (break point on print line is not being hit).
Any help is appreciated!
Please make sure to set the delegate property of mapview to self.
mapview.delegate = self
You can also do this by connecting the delegate outlet of mapview to ViewController using Connection Inspector (Interface Builder)