I have just started learning Swift.
Question:
When I touch on map to place the pin annotation and drag my finger it creates repeating line of annotation.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var map: MKMapView!
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
//Manager for current location
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
//Getting touch Gesture to add bookmark
let uilpgr = UILongPressGestureRecognizer(target: self, action: "action:")
uilpgr.minimumPressDuration = 1
uilpgr.numberOfTouchesRequired = 1
map.addGestureRecognizer(uilpgr)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0]
let latitude:CLLocationDegrees = userLocation.coordinate.latitude
let longitude:CLLocationDegrees = userLocation.coordinate.longitude
let latDelta:CLLocationDegrees = 0.002
let lonDelta:CLLocationDegrees = 0.002
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
map.setRegion(region, animated: true)
}
func action(gestureRecognizer: UIGestureRecognizer) {
let touchPoint = gestureRecognizer.locationInView(self.map)
let newCoordinate: CLLocationCoordinate2D = map.convertPoint(touchPoint, toCoordinateFromView: self.map)
print(newCoordinate)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
annotation.title = "New Place"
annotation.subtitle = "One day I'll go here..."
map.addAnnotation(annotation)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Xcode 8.2 • Swift 3.0.2
You just need to check the gesture recognizer state and make sure if not .Began return. Just add this if condition at the top of your action method:
func action(_ gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.state != UIGestureRecognizerState.began {
return
}
// your code
If you would like to allow the user to move the pin while touching you will need to switch the gesture recognizer state and update the annotation coordinate if gestureRecognizer.state changes:
func action(_ gestureRecognizer: UIGestureRecognizer) {
switch gestureRecognizer.state {
case .began:
let annotation = MKPointAnnotation()
annotation.coordinate = mapView.convert(gestureRecognizer.location(in: mapView), toCoordinateFrom: mapView)
annotation.title = "Untitled"
mapView.addAnnotation(annotation)
case .changed:
if let annotation = (mapView.annotations.filter{$0.title! == "Untitled" }).first as? MKPointAnnotation {
annotation.coordinate = mapView.convert(gestureRecognizer.location(in: mapView), toCoordinateFrom: mapView)
}
case .cancelled:
if let annotation = (mapView.annotations.filter{$0.title! == "Untitled" }).first as? MKPointAnnotation {
mapView.removeAnnotation(annotation)
}
// you can also prompt the user here for the annotation title
case .ended:
if let annotation = (mapView.annotations.filter{$0.title! == "Untitled" }).first as? MKPointAnnotation {
let alert = UIAlertController(title: "New Annotation", message: "", preferredStyle: .alert)
var inputTextField: UITextField?
alert.addAction(UIAlertAction(title: "Add", style: .default) { _ in
if let annotationTitle = inputTextField?.text {
annotation.title = annotationTitle
annotation.subtitle = "Lat:\(String(format: "%.06f", annotation.coordinate.latitude)) Lon:\(String(format: "%.06f", annotation.coordinate.longitude))"
}
})
alert.addTextField(configurationHandler: { textField in
textField.placeholder = "Place Description"
inputTextField = textField
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel){ _ in
self.mapView.removeAnnotation(annotation)
})
present(alert, animated: true, completion: nil)
}
default:
print("default")
}
}
Related
I want save manually location on map.I am tap on map and printing manually location. But my code(savemyadress) save current location. How should I edit code. Thanks
import UIKit
import MapKit
import Firebase
class MapViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var saveButton : UIBarButtonItem!
#IBOutlet var tapGesture: UITapGestureRecognizer!
let locationManager = CLLocationManager()
var ref: DatabaseReference!
var adres: Adresler!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
}
func savemyadress(){
let sender = self.tapGesture
//if sender!.state == .ended{
let locationInView = sender!.location(in: mapView)
let tappedCoordinate = mapView.convert(locationInView, toCoordinateFrom: mapView)
let coordinateRegion = MKCoordinateRegion(center: tappedCoordinate, latitudinalMeters: 400, longitudinalMeters: 400)
mapView.setRegion(coordinateRegion, animated: true)
let userRef = self.ref.child("locations").child("Address")
let coordinate = tappedCoordinate
let adres = Adresler(latitude: coordinate.latitude , longitude: coordinate.longitude)
let Locations = userRef.childByAutoId()
let adresRef = Locations
adresRef.setValue(adres.toDictionary())
//}
}
#IBAction func tapGesture(_ sender: UITapGestureRecognizer) {
if sender.state == .ended{
let locationInView = sender.location(in: mapView)
let tappedCoordinate = mapView.convert(locationInView, toCoordinateFrom:mapView)
print(tappedCoordinate.latitude, tappedCoordinate.longitude)
}}}
extension MapViewController : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last! as CLLocation
let currentLocation = location.coordinate
let coordinateRegion = MKCoordinateRegion(center: currentLocation, latitudinalMeters: 400, longitudinalMeters: 400)
mapView.setRegion(coordinateRegion, animated: true)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
guard let placemark = placemarks?.last else {
let errorString = error?.localizedDescription ?? "Unexpected Error"
return}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error:: (error)")}}
UPDATE
#IBAction func saveButton(_ sender: Any) {
let alert = UIAlertController(title: "Address", message: "Save address", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { [self]action in
savemyadress()
_ = self.navigationController?.popViewController(animated: true)
}))
self.present(alert, animated: true)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I tried to add an annotation in my map when I click the button. I have written some codes but I am not getting any annotation based on my current location.
#IBAction func addPressed(_ sender: Any) {
guard let location = self.locationManager.location else {
return
}
let annotation = MKPointAnnotation()
annotation.title = "Flooded"
annotation.subtitle = "Reported on 12/10/2018 8:50 AM"
annotation.coordinate = location.coordinate
self.mapView.addAnnotation(annotation)
}
Add this to your view controller and also make sure to assign delegate to self for mapView in viewDidLoad()
Update: As dicsussed in comments, replace your complete view controller code with the code below.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var add: UIButton!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
checkLocationServices()
}
func setupLocationManager () {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorization()
} else {
}
}
func checkLocationAuthorization () {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
let alert = UIAlertController(title: "Location Services disabled", message: "Please enable Location Services in Settings", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
case .denied:
let alert = UIAlertController(title: "Location Services disabled", message: "Please enable Location Services in Settings", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
case .authorizedAlways:
break
case .authorizedWhenInUse:
mapView.showsUserLocation = true // this will bring the blue dot on map
centreZoomviewUserLocation()
locationManager.startUpdatingLocation()
#unknown default:
break
}
}
func centreZoomviewUserLocation () {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: true)
}
}
//MARK:- Button pressed
#IBAction func addPressed(_ sender: Any) {
guard let location = self.locationManager.location else {
return
}
let annotation = MKPointAnnotation()
annotation.title = "Flooded"
annotation.subtitle = "Reported on 12/10/2018 8:50 AM"
annotation.coordinate = location.coordinate
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newPin = MKPointAnnotation()
guard let location = locations.last else { return }
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion.init(center: center, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: true)
newPin.coordinate = location.coordinate
mapView.addAnnotation(newPin)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
}
extension ViewController : MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard annotation is MKPointAnnotation else { return nil }
let identifier = "Annotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
} else {
annotationView!.annotation = annotation
}
return annotationView
}
}
So, at the moment I can't seem to figure out how the user can enter a title on the Annotation pins. In my code a pin will appear after a long press on the map, but the title shown of the pin is "Pin".
The only thing I would like to be able to do is for the user of the app to be able to create unique titles of the pins on creation.
import Foundation
import UIKit
import MapKit
class MapsViewController: UIViewController, CLLocationManagerDelegate {
let locationManager:CLLocationManager = CLLocationManager()
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for currentLocation in locations{
print("\(index) : \(currentLocation)")
}
}
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let alert = UIAlertController(title: "Title", message: "Please enter location name", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.text = "Location name"
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(String(describing: textField?.text))")
DispatchQueue.main.async { self.addPinWithTitle (sender , title : textField?.text ?? "") }
}))
self.present(alert, animated: true, completion: nil)}
func addPinWithTitle(_ sender: UILongPressGestureRecognizer , title : String) {
let location = sender.location(in: self.mapView)
let locCoordinates = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoordinates
annotation.title = title
self.mapView.addAnnotation(annotation)}
}
Please follow the final code
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let alert = UIAlertController(title: "Title", message: "Please enter location name", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.placeholder = "Location name"
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(textField?.text)")
DispatchQueue.main.async {
self.addPinWithTitle (sender , title : textField?.text ?? "")
}
}))
self.present(alert, animated: true, completion: nil)}
func addPinWithTitle(_ sender: UILongPressGestureRecognizer , title : String) {
let location = sender.location(in: self.mapView)
let locCoordinates = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoordinates
annotation.title = title
self.mapView.addAnnotation(annotation)}
I'm trying to show my current location on simulator but it displays another location
import UIKit
import MapKit
class DriverVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var myMap: MKMapView!
let locationManager = CLLocationManager()
var driverLocation : CLLocationCoordinate2D?
var userLocation : CLLocationCoordinate2D?
override func viewDidLoad() {
super.viewDidLoad()
intializeLocationManager()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locationManager.location?.coordinate {
print("location\(location)")
myMap.removeAnnotations(myMap.annotations)
driverLocation = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
let region = MKCoordinateRegion(center: driverLocation!, span: MKCoordinateSpanMake(0.07, 0.07))
myMap.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = driverLocation!
annotation.title = "driver location"
myMap.addAnnotation(annotation)
}
}
private func intializeLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
#IBAction func signOut(_ sender: UIBarButtonItem) {
if (AuthProvider.Instance.logOut()){
dismiss(animated: true, completion: nil)
}
else{
alertTheUser(title: "couldn't sign out", message: "try again")
}
}
#IBAction func answer(_ sender: UIButton) {
}
private func alertTheUser(title: String, message: String){
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(ok)
present(alert,animated: true, completion: nil)
}
}
I added Location when in usage description to Info.plist and the simulator debug location is non
I am trying to run just a simple print function when the user moves the map around using gesture or search (moves the map in general) I've followed the apple ref guides and i get errors. Ive followed other stack overflow posts and other google search results. I don't know if it is because im using swift 2 or something in my code elsewhere that is contradicting. If somebody could help me that would be greatly appreciated. Here is my code
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate,
CLLocationManagerDelegate, UISearchBarDelegate
{
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var searchBar: UISearchBar!
let locationManager = CLLocationManager()
#IBAction func showSearchBar(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.delegate = self
presentViewController(searchController, animated: true, completion: nil)
}
#IBAction func locateMe(sender: AnyObject) {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
#IBAction func photographer(sender: AnyObject) {
}
#IBAction func buyer(sender: AnyObject) {
}
var searchController:UISearchController!
var annotation:MKAnnotation!
var localSearchRequest:MKLocalSearchRequest!
var localSearch:MKLocalSearch!
var localSearchResponse:MKLocalSearchResponse!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
override func viewDidLoad()
{
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
hobo()
}
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Error: " + error.localizedDescription)
}
func searchBarSearchButtonClicked(searchBar: UISearchBar){
//1
searchBar.resignFirstResponder()
dismissViewControllerAnimated(true, completion: nil)
if self.mapView.annotations.count != 0{
annotation = self.mapView.annotations[0]
self.mapView.removeAnnotation(annotation)
}
//2
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in
if localSearchResponse == nil{
let alertController = UIAlertController(title: nil, message: "Place Not Found", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
return
}
//3
self.pointAnnotation = MKPointAnnotation()
self.pointAnnotation.title = searchBar.text
self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: localSearchResponse!.boundingRegion.center.latitude, longitude: localSearchResponse!.boundingRegion.center.longitude)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.pointAnnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation!)
}
}
func hobo(){
print("testing")
}
}
Make sure you set yourself as your map view's delegate in IB. Also, I'd try moving regionDidChangeAnimated out of viewDidLoad.