MapKit- How to add location constraints for dropping a pin? - ios

I have an application that allows users to drop a pin anywhere on their map (MapKit), and it currently identifies and displays their current location. I would like to set a constraint so that users are unable drop a pin any further than 10 miles from their current location. Is this doable? I am somewhat new to dev, so I am not sure where to begin doing this. Here's a bit of the code that deals with dropping pin:
#IBOutlet weak var mapView: MKMapView!
//addpin
#IBAction func addPin(sender: UILongPressGestureRecognizer) {
//locating where to drop the pin
let location = sender.locationInView(self.mapView)
let locCoord = self.mapView.convertPoint(location, toCoordinateFromView:
self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = "Test"
annotation.subtitle = "subtext"
//remove map point (use later)
self.mapView.removeAnnotations(mapView.annotations)
self.mapView.addAnnotation(annotation)
}

You can use distance(from: ) method.
See: https://developer.apple.com/documentation/corelocation/cllocation/1423689-distance
#IBAction func addPin(sender: UILongPressGestureRecognizer) {
//locating where to drop the pin
let location = sender.locationInView(self.mapView)
let locCoord = self.mapView.convertPoint(location, toCoordinateFromView:
self.mapView)
// Get distance between pressed location and user location
let pressedLocation = CLLocation(latitude: locCoord.latitude, longitude: locCoord.longitude)
// let distanceInMeters = self.mapView.userLocation.location?.distance(from: pressedLocation) // >= Swift 3
let distanceInMeters = self.mapView.userLocation.location?.distanceFromLocation(pressedLocation) // < Swift 3
// You get here distance in meter so 10 miles = 16090 meter
if let distanceInMeters = distanceInMeters, distanceInMeters > 16090 {
// out of 10 mile (don't drop pin)
return
}
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = "Test"
annotation.subtitle = "subtext"
//remove map point (use later)
self.mapView.removeAnnotations(mapView.annotations)
self.mapView.addAnnotation(annotation)
}
However, there are couple of things that you need to put in place first.
You need to ask the user for permission to use their location. That includes calling CLLocationManager's requestWhenInUseAuthorization and checking for the asynchronous result.
Adding NSLocationWhenInUseUsageDescription entry to your info (described in the link above) to tell the user what you want to do with the information

Related

Swift 3 - LongPress on GMSMarker and print its coordinates (Google Maps iOS SDK)

Using Google Maps iOS SDK, I want to be able to print the coordinates of a GMSMarker if long pressed on that particular marker.
I first get all of my coordinates from a dictionary and drop markers for all coordinates on the map:
func placeMapMarkers() {
for item in self.finalDictionary as [Dictionary<String, String>] {
let lat = item["lat"] as! String
let lon = item["lon"] as! String
let SpotLat = Double(lat)
let SpotLon = Double(lon)
let SpotLocation = CLLocationCoordinate2DMake(SpotLat!, SpotLon!)
DispatchQueue.main.async(execute: {
self.SpotMarker = GMSMarker(position: SpotLocation)
self.SpotMarker?.icon = self.imageWithImage(image: UIImage(named: "SpotIcon")!, scaledToSize: CGSize(width: 35.0, height: 35.0))
self.SpotMarker?.title = "Long press to navigate here"
self.SpotMarker?.map = self.mapView
})
longPress(mapView: self.mapView, didLongPressAtCoordinate: SpotLocation)
}
}
My longPress function call is in the above placeMapMarkers function itself, since I want to identify while placing markers itself if a particular marker has been long pressed (I could be wrong with my thinking here).
My longPress function is below.
//This is long Press function:-
func longPressView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
//Here handle your long press on map marker like:-
print("long pressed at \(coordinate)")
}
The problem is that I am getting "long pressed at" all coordinates from the dictionary of coordinates.
I want to
place markers for all coordinates in a dictionary
long press on a particular marker
and print coordinates for only that particular marker which was long pressed.
How do I go about this? Had a look at the other solutions, wasn't able to work out much.
I looked through the GMSMapView API. There is a method called "didLongPressAtCoordinate" that passes in a CLLocationCoordinate2D, so I think you can use that to create a GMSMarker. See here
You have to implement the GMSMapViewDelegate, and you can call
func mapView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
let marker = GMSMarker(position: coordinate)
marker.title = "Found You!"
marker.map = mapView
}
Hope this one helps :)
I have done this before. You basically have to convert the touch point on the map to a coordinate.
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
let uilpgr = UILongPressGestureRecognizer(target: self, action: #selector(userPerformedLongPress(gesture:)))
uilpgr.minimumPressDuration = 2.0
}
func userPerformedLongPress(gesture: UIGestureRecognizer) {
let touchPoint = gesture.location(in: mapView)
let newCoordinate: CLLocationCoordinate2D = mapView.convert(touchPoint, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
annotation.title = "Location Selected"
annotation.subtitle = "Coordinate: \(round(1000*newCoordinate.longitude)/1000), \(round(1000*newCoordinate.latitude)/1000)"
mapView.addAnnotation(annotation)
print("Gesture recognized")
}

How to extract lat/long placemark.coordinate in Swift?

I added a location search bar to my app. The tableview controller consists of the user location lat/long as well as the destination (address the user inputs into the search bar). As far as I can tell the latitude / longitude is within the placemark.coordinate:
placemark.coordinate = CLLocationCoordinate2D(latitude: 45.253519203737767, longitude: -66.070974382763978)
I have two variables: destLat and destLong. How I can extract the latitude and longitude from placemark.coordinate and place into the two variables mentioned above?
related code:
// cache the pin
selectedPin = placemark
// clear existing pins
mapView.removeAnnotations(mapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let prov = placemark.administrativeArea {
annotation.subtitle = "\(city), \(prov)"
}
let destination = placemark.coordinate
print("Destination coordinates: \(destination)")
let name = placemark.name
print("Placemark Name: \(name!)")
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
Console output:
Perhaps your were thinking too hard. You can assign values to these variables just like any other:
let (destLat, destLong) = (placemark.coordinate.latitude, placemark.coordinate.longitude)
If both variable you have declare is type of Double then you need to simply need to access the latitude and longitude property of CLLocationCoordinate2D.
destLat = destination.latitude
destLong = destination.longitude
If type of both var is different then simply change it to Double works for you.

how can I fetch the longitude and latitude from a specific point on my mapview in swift?

I have a MKMapView in my app and currently I'm fetching the center point of this map by using:
longitude = mapView.centerCoordinate.longitude
latitude = mapView.centerCoordinate.latitude
but now instead of taking the center point of the map I want to take a specific point that is 100px below the top edge of my mapview. So normally I would use something like:
longitude = mapView.centerCoordinate.longitude
latitude = mapView.(centerCoordinate+100px).latitude
But that's not how that works apparently. Is there any way of fetching a specific point from mkmapview?
Try this:
let frame = mapView.frame
let myPoint = CGPointMake(frame.midX, 100)
let myCoordinate = mapView.convertPoint(myPoint, toCoordinateFromView: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = myCoordinate
annotation.title = "My Point"
mapView.addAnnotation(annotation)
Used the the MapKit method:
convertPoint:toCoordinateFromView:

Adding a pin annotation to a map view on a long press in swift

I'm trying to make an iPhone app which requires users to be able to long press on a place on a map view to drop a pin there. Does anybody know how this is done?
The behaviour is observable in apple maps when you long press on the screen. It will drop a pin and present an annotation saying "dropped pin"
add UILongPressGestureRecognizer to your MapView
var uilgr = UILongPressGestureRecognizer(target: self, action: "addAnnotation:")
uilgr.minimumPressDuration = 2.0
map.add (uilgr)
//IOS 9
map.addGestureRecognizer(uilgr)
Add annotation on Long press detect - func:
func addAnnotation(gestureRecognizer:UIGestureRecognizer){
if gestureRecognizer.state == UIGestureRecognizerState.Began {
var touchPoint = gestureRecognizer.locationInView(map)
var newCoordinates = map.convertPoint(touchPoint, toCoordinateFromView: map)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinates
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinates.latitude, longitude: newCoordinates.longitude), completionHandler: {(placemarks, error) -> Void in
if error != nil {
println("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0 {
let pm = placemarks[0] as! CLPlacemark
// not all places have thoroughfare & subThoroughfare so validate those values
annotation.title = pm.thoroughfare + ", " + pm.subThoroughfare
annotation.subtitle = pm.subLocality
self.map.addAnnotation(annotation)
println(pm)
}
else {
annotation.title = "Unknown Place"
self.map.addAnnotation(annotation)
println("Problem with the data received from geocoder")
}
places.append(["name":annotation.title,"latitude":"\(newCoordinates.latitude)","longitude":"\(newCoordinates.longitude)"])
})
}
}
or you can add annotation without any title:
func action(gestureRecognizer:UIGestureRecognizer){
var touchPoint = gestureRecognizer.locationInView(map)
var newCoordinates = map.convertPoint(touchPoint, toCoordinateFromView: map)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinates
map.addAnnotation(annotation)
}
1) Instantiate a UILongPressGestureRecognizer and add it to the MKMapView.
2) When the selector gets called after the user has a long press, call the addAnnotation method in MKMapView with the appropriate title and coordinate.
3) Then make sure you conform to the MKMapViewDelegate and implement viewForAnnotation: which will be called right after you add the annotation and return a MKPinAnnotationView
First declare UIGestureRecognizer in viewDidLoad
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(addWaypoint(longGesture:)))
mapView.addGestureRecognizer(longGesture)
Second add the function for longPress
#objc func addWaypoint(longGesture: UIGestureRecognizer) {
let touchPoint = longGesture.location(in: mapView)
let wayCoords = mapView.convert(touchPoint, toCoordinateFrom: mapView)
let location = CLLocation(latitude: wayCoords.latitude, longitude: wayCoords.longitude)
myWaypoints.append(location)
let wayAnnotation = MKPointAnnotation()
wayAnnotation.coordinate = wayCoords
wayAnnotation.title = "waypoint"
myAnnotations.append(wayAnnotation)
}
I recommend creating the annotations in an array that will serve you later if you want to delete it, like this...
var myAnnotations = [MKPointAnnotation]()
If you have different annotations, you can delete only the annotations you want, for that when you add a new annotation add to the array. To delete only one group of annotations just do the following
for dots in myAnnotations{
mapView.removeAnnotation(dots)
}
To delete all annotations try
mapView.removeAnnotations(mapView.annotations)
Apologies for the translation....
Update Swift3
func action(gestureRecognizer:UIGestureRecognizer){
let touchPoint = gestureRecognizer.location(in: mapView)
let newCoordinates = mapView.convert(touchPoint, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinates
mapView.addAnnotation(annotation)
}

How to set visible region/zoom level for google maps IOS to show all markers added to the mapview

I have used Google maps in ios app, I wanna set zoom level dynamically depends on the search i made over map. Basically am adding pins by searching with city names or lat/long query. after every search am adding pins & i need to show all added markers by the recent search i made.
#IBOutlet weak var mapView: GMSMapView!
let camera = GMSCameraPosition.cameraWithLatitude(23.0793, longitude:
72.4957, zoom: 5)
mapView.camera = camera
mapView.delegate = self
mapView.myLocationEnabled = true
*** arry has dictionary object which has value of Latitude and Longitude. ***
let path = GMSMutablePath()
for i in 0..<arry.count {
let dict = arry[i] as! [String:AnyObject]
let latTemp = dict["latitude"] as! Double
let longTemp = dict["longitude"] as! Double
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: latTemp, longitude: longTemp)
marker.title = "Austrilia"
marker.appearAnimation = kGMSMarkerAnimationNone
marker.map = self.mapView
path.addCoordinate(CLLocationCoordinate2DMake(latTemp, longTemp))
}
let bounds = GMSCoordinateBounds(path: path)
self.mapView!.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 50.0))
See this answer for a simple way to iterate over a given array of markers and then set the bounds accordingly.

Resources