Good afternoon Community,
I am having trouble plotting the Poly Line within my application, I already tried calling it in the func method locationManager (_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {}
but nothing is generated, just as I would like each step that I take the polyline to be marked and not at the end of my journey. I leave my code below:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate,MKMapViewDelegate {
#IBOutlet var Maps: MKMapView!
var locationManager = CLLocationManager()
var coordenadas = CLLocationCoordinate2D()
var startPoint = MKDirections.Request()
var ArrayDeCoordenadas: [CLLocationCoordinate2D] = []
var tap: Int = 0
func getDirections(){
let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.requestsAlternateRoutes = true
let directions = MKDirections(request: request)
directions.calculate { (response, error) in
if error != nil {
print("Error \(error)")
} else {
//self.dispLayRout(response)
var overlays = self.Maps.overlays
self.Maps.removeOverlays(overlays)
for route in response!.routes as! [MKRoute] {
self.Maps.addOverlay(route.polyline,
level: MKOverlayLevel.aboveRoads)
var instructionNumber = 0
for next in route.steps {
instructionNumber += 1
print(next.instructions)
}
}
}
}
}
func alertLocation(title: String, Message:String){
let alert = UIAlertController(title: title, message: Message, preferredStyle: .alert)
let actionAlert = UIAlertAction(title: "Acept", style: .default, handler: nil)
alert.addAction(actionAlert)
self.present(alert, animated: true,completion: nil)
}
func LocalizationInit(){
let autorization = CLLocationManager.authorizationStatus()
switch autorization{
case .notDetermined, .restricted:
locationManager.requestLocation()
break;
case .restricted, .denied:
alertLocation(title: "We have a Error", Message: "You have your localization restricted.")
case .authorizedAlways,.authorizedWhenInUse:
break;
default:
break;
}
}
#IBAction func Share(_ sender: UIButton) {
let compartir = UIActivityViewController(activityItems: ["Share baby" as Any],
applicationActivities: nil)
compartir.popoverPresentationController?.sourceView = self.view
present(compartir,animated: true,completion: nil)
}
#IBAction func recordButton(_ sender: UIButton) {
if sender.isSelected != true {
tap += 1
print("tap -> :\(tap)")
if tap == 1{
let annotation = MKPointAnnotation()
annotation.title = "My route"
annotation.subtitle = "I Hoppe"
annotation.coordinate = coordenadas
let annotation2 = MKPointAnnotation()
annotation2.title = "My ride"
annotation2.subtitle = "I Hoppe"
annotation.coordinate = locationManager.location?.coordinate as! CLLocationCoordinate2D
self.Maps.addAnnotation(annotation)
}else if tap == 2 {
tap = 0
locationManager.stopMonitoringSignificantLocationChanges()
}
}
}
#IBAction func mapOptions(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex{
case 0:
Maps.mapType = MKMapType.standard
break;
case 1:
Maps.mapType = MKMapType.satellite
break;
case 2:
Maps.mapType = MKMapType.hybrid
break;
default:
break;
}
}
override func viewDidLoad() {
super.viewDidLoad()
LocalizationInit()
let polyLineMake = MKPolyline(coordinates: ArrayDeCoordenadas, count: ArrayDeCoordenadas.count)
self.Maps.addOverlay(polyLineMake, level: .aboveRoads)
Maps.showsUserLocation = true
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
DispatchQueue.main.async {
self.locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
coordenadas = manager.location?.coordinate as! CLLocationCoordinate2D
ArrayDeCoordenadas.append(locations.last!.coordinate)
print("Array de coordenadas : -> \(ArrayDeCoordenadas)")
let region = MKCoordinateRegion(center: locations.last!.coordinate, latitudinalMeters: 200,
longitudinalMeters: 200)
self.Maps.setRegion(region, animated: false)
let distancia = locations.distance(from: Int(manager.location!.coordinate.latitude), to:
Int((locations.last?.coordinate.latitude)!))
print("distancia \(distancia)")
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation{
return nil
}
let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "My personal pin")
pin.pinTintColor = UIColor.green
return pin
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline{
let polyline = overlay
let polyLineRender = MKPolylineRenderer(overlay: polyline)
print(" se esta generando \(polyline)")
polyLineRender.strokeColor = UIColor.red
polyLineRender.lineWidth = 6.0
return polyLineRender
}
print(" no se esta generando")
return MKPolylineRenderer()
} }
I have read the documentation a bit and apparently my code is fine, if someone could help me, it would be of great help! Like someone if you have any method that can help me to know when I did and how many steps I walked since I did not see that CLLocation had an option for that type of information.
the problem is not set Map delegate object, also I made some changes to add polyline overlay. Simple but it is working. Good luck.
Maps.delegate = self
Code file:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate,MKMapViewDelegate {
#IBOutlet var Maps: MKMapView!
var locationManager = CLLocationManager()
var coordenadas = CLLocationCoordinate2D()
var startPoint = MKDirections.Request()
var ArrayDeCoordenadas: [CLLocationCoordinate2D] = []
var tap: Int = 0
var journeyPolyline: MKPolyline?
func getDirections(){
let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.requestsAlternateRoutes = true
let directions = MKDirections(request: request)
directions.calculate { (response, error) in
if error != nil {
print("Error \(error)")
} else {
//self.dispLayRout(response)
var overlays = self.Maps.overlays
self.Maps.removeOverlays(overlays)
for route in response!.routes as! [MKRoute] {
self.Maps.addOverlay(route.polyline,
level: MKOverlayLevel.aboveRoads)
var instructionNumber = 0
for next in route.steps {
instructionNumber += 1
print(next.instructions)
}
}
}
}
}
func alertLocation(title: String, Message:String){
let alert = UIAlertController(title: title, message: Message, preferredStyle: .alert)
let actionAlert = UIAlertAction(title: "Acept", style: .default, handler: nil)
alert.addAction(actionAlert)
self.present(alert, animated: true,completion: nil)
}
func LocalizationInit(){
let autorization = CLLocationManager.authorizationStatus()
switch autorization{
case .notDetermined, .restricted:
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
break;
case .restricted, .denied:
alertLocation(title: "We have a Error", Message: "You have your localization restricted.")
case .authorizedAlways,.authorizedWhenInUse:
locationManager.startUpdatingLocation()
break;
default:
break;
}
}
#IBAction func Share(_ sender: UIButton) {
let compartir = UIActivityViewController(activityItems: ["Share baby" as Any],
applicationActivities: nil)
compartir.popoverPresentationController?.sourceView = self.view
present(compartir,animated: true,completion: nil)
}
#IBAction func recordButton(_ sender: UIButton) {
if sender.isSelected != true {
tap += 1
print("tap -> :\(tap)")
if tap == 1{
let annotation = MKPointAnnotation()
annotation.title = "My route"
annotation.subtitle = "I Hoppe"
annotation.coordinate = coordenadas
let annotation2 = MKPointAnnotation()
annotation2.title = "My ride"
annotation2.subtitle = "I Hoppe"
annotation.coordinate = locationManager.location?.coordinate as! CLLocationCoordinate2D
self.Maps.addAnnotation(annotation)
}else if tap == 2 {
tap = 0
locationManager.stopMonitoringSignificantLocationChanges()
}
}
}
#IBAction func mapOptions(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex{
case 0:
Maps.mapType = MKMapType.standard
break;
case 1:
Maps.mapType = MKMapType.satellite
break;
case 2:
Maps.mapType = MKMapType.hybrid
break;
default:
break;
}
}
override func viewDidLoad() {
super.viewDidLoad()
LocalizationInit()
// let polyLineMake = MKPolyline(coordinates: ArrayDeCoordenadas, count: ArrayDeCoordenadas.count)
// self.Maps.addOverlay(polyLineMake, level: .aboveRoads)
Maps.showsUserLocation = true
Maps.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
coordenadas = locations.first!.coordinate as! CLLocationCoordinate2D
ArrayDeCoordenadas.append(locations.last!.coordinate)
print("Array de coordenadas : -> \(ArrayDeCoordenadas)")
let region = MKCoordinateRegion(center: locations.last!.coordinate, latitudinalMeters: 200,
longitudinalMeters: 200)
self.Maps.setRegion(region, animated: false)
let distancia = locations.distance(from: Int(manager.location!.coordinate.latitude), to:
Int((locations.last?.coordinate.latitude)!))
print("distancia \(distancia)")
let polyline = MKPolyline(coordinates: ArrayDeCoordenadas, count: ArrayDeCoordenadas.count)
Maps.addOverlay(polyline)
//remove old polyline
if let oldPolyline = journeyPolyline {
Maps.removeOverlay(oldPolyline)
}
journeyPolyline = polyline
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation{
return nil
}
let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "My personal pin")
pin.pinTintColor = UIColor.green
return pin
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline{
let polyline = overlay
let polyLineRender = MKPolylineRenderer(overlay: polyline)
print(" se esta generando \(polyline)")
polyLineRender.strokeColor = UIColor.red
polyLineRender.lineWidth = 6.0
return polyLineRender
}
print(" no se esta generando")
return MKPolylineRenderer()
}
}
Related
I am creating my first IOS app and am having a very difficult time understanding why the CalloutAccessoryControlTapped Control function is not working.
The Info button is appearing on the annotation, but when the user taps on the Info button, nothing happens. See screenshot here: Screenshot of Annotation.
I created a function in the View Controller to add the Callout accessory view and suspect there is something wrong with the function.
Any help would be greatly appreciated!
Here is the Function:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let annotation = view.annotation as? Fire
let status = "Fire Status: Active"
let distance = "Fire Location: 25 miles away"
let ac = UIAlertController(title: status, message: distance, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Close", style: .default))
self.present(ac, animated: true, completion: nil)
}
Here is the code from my View Controller -- updated 4/20/2021:
import MapKit
import UIKit
import CoreLocation
class FireMapViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var FireMapView: MKMapView!
let mapView = MKMapView()
var locationManager = CLLocationManager()
var lat = Double()
var lon = Double()
var fires: [Fire] = []
override func viewDidLoad() {
super.viewDidLoad()
setupMapView()
checkLocationServices()
mapView.register(FireMarkerView.self,forAnnotationViewWithReuseIdentifier:
MKMapViewDefaultAnnotationViewReuseIdentifier)
//Initiate URL Session to get Fire data and add Fire data to the Map Annotations
if let url = URL(string: "https://services3.arcgis.com/T4QMspbfLg3qTGWY/arcgis/rest/services/Active_Fires/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson") {
URLSession.shared.dataTask(with: url) {data, response, error in
if let data = data {
do {
let features = try MKGeoJSONDecoder().decode(data)
.compactMap { $0 as? MKGeoJSONFeature }
let validWorks = features.compactMap(Fire.init)
self.fires.append(contentsOf: validWorks)
DispatchQueue.main.async {
self.mapView.addAnnotations(self.fires)
}
}
catch let error {
print(error)
}
}
}.resume()
}
}
func setupMapView() {
view.addSubview(mapView)
mapView.translatesAutoresizingMaskIntoConstraints = false
mapView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
mapView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
mapView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
locationManagerDidChangeAuthorization(locationManager)
} else {
// the user didn't turn it on
}
}
//Get the current location permissions for User
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedAlways , .authorizedWhenInUse:
mapView.showsUserLocation = true
followUserLocation()
locationManager.startUpdatingLocation()
break
case .notDetermined , .denied , .restricted:
locationManager.requestWhenInUseAuthorization()
break
default:
break
}
switch manager.accuracyAuthorization {
case .fullAccuracy:
break
case .reducedAccuracy:
break
default:
break
}
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let region = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: 160934, longitudinalMeters: 160934)
mapView.setRegion(region, animated: true)
print("Fire Map User Location on Map:", location.coordinate)
// Call stopUpdatingLocation() to stop listening for location updates,
// other wise this function will be called every time when user location changes.
// Need a solution for this.
manager.stopUpdatingLocation()
}
func followUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 4000, longitudinalMeters: 4000)
mapView.setRegion(region, animated: true)
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationManagerDidChangeAuthorization(locationManager)
}
//Function to display additional Fire data after User selects the Callout Info button on the Annotation
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let annotation = view.annotation as? Fire
print("callout Accessory Tapped!")
let status = "Fire Status: Active"
let distance = "Fire Location: 25 miles away"
let ac = UIAlertController(title: status, message: distance, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Close", style: .default))
self.present(ac, animated: true, completion: nil)
}
}
Here is the Class for the Annotation:
import Foundation
import MapKit
class FireMarkerView: MKAnnotationView {
override var annotation: MKAnnotation? {
willSet {
guard let fire = newValue as? Fire else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
image = fire.image
}
}
}
Here is the Class for the Model:
import Foundation
import MapKit
class Fire: NSObject, MKAnnotation {
let title: String?
let county: String?
let city: String?
let incidentTypeCategory: String?
let coordinate: CLLocationCoordinate2D
let percentContained: Int?
let lastUpdateDateTime: Int?
init(
title: String?,
county: String?,
city: String?,
incidentTypeCategory: String?,
coordinate: CLLocationCoordinate2D,
percentContained: Int?,
lastUpdateDateTime: Int?
) {
self.title = title
self.county = county
self.city = city
self.incidentTypeCategory = incidentTypeCategory
self.coordinate = coordinate
self.percentContained = percentContained
self.lastUpdateDateTime = lastUpdateDateTime
super.init()
}
init?(feature: MKGeoJSONFeature) {
// 1
guard
let point = feature.geometry.first as? MKPointAnnotation,
let propertiesData = feature.properties,
let json = try? JSONSerialization.jsonObject(with: propertiesData),
let properties = json as? [String: Any]
else {
return nil
}
// 2
title = ((properties["IncidentName"] as? String ?? "Unknown") + " Wildfire")
county = ((properties["POOCounty"] as? String ?? "Unknown") + " County")
city = properties["POOCity"] as? String
incidentTypeCategory = properties["IncidentTypeCategory"] as? String
coordinate = point.coordinate
percentContained = properties["PercentContained"] as? Int
lastUpdateDateTime = properties["ModifiedOnDateTime_dt"] as? Int
super.init()
}
var subtitle: String? {
return (county)
}
var image: UIImage {
guard let name = incidentTypeCategory else {
return #imageLiteral(resourceName: "RedFlame")
}
switch name {
case "RX":
return #imageLiteral(resourceName: "YellowFlame")
default:
return #imageLiteral(resourceName: "RedFlame")
}
}
}
I need some help to solve this problem. So, I have a turn-by-turn navigation where when user search for places and it will give turn-by-turn navigation. But, when user deletes the places name, but it still shows on the map view. Is there a way I can delete the map view when user deletes the places or address name? Thanks for the help.
here is my code:
import UIKit
import MapKit
import CoreLocation
import AVFoundation
class NavigateVC: UIViewController {
#IBOutlet weak var directionLabel: UILabel!
#IBOutlet weak var search: UISearchBar!
#IBOutlet weak var mapa: MKMapView!
let locationManager = CLLocationManager()
var currentCoordinate: CLLocationCoordinate2D!
var steps = [MKRouteStep]()
let speechSynthesizer = AVSpeechSynthesizer()
var stepCounter = 0
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.startUpdatingLocation()
// Show an alert view to the user - as a new feature to the app.
let alert = UIAlertController(title: "Welcome", message: "You can now navigate to your favorite place with turn-by-turn navigation. Simply, enter a place name or full address to navigate to your destination. Note: Multiple destination navigation will show on the map view. Choose your destination wisely. ", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
switch action.style{
case .default:
print("default")
case .cancel:
print("cancel")
case .destructive:
print("destructive")
}}))
self.present(alert, animated: true, completion: nil)
}
func getDirections(to destination: MKMapItem) {
let sourcePlacemark = MKPlacemark(coordinate: currentCoordinate)
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
let directionsRequest = MKDirectionsRequest()
directionsRequest.source = sourceMapItem
directionsRequest.destination = destination
directionsRequest.transportType = .automobile
let directions = MKDirections(request: directionsRequest)
directions.calculate { (response, _) in
guard let response = response else { return }
guard let primaryRoute = response.routes.first else { return }
self.mapa.add(primaryRoute.polyline)
self.locationManager.monitoredRegions.forEach({ self.locationManager.stopMonitoring(for: $0) })
self.steps = primaryRoute.steps
for i in 0 ..< primaryRoute.steps.count {
let step = primaryRoute.steps[i]
print(step.instructions)
print(step.distance)
let region = CLCircularRegion(center: step.polyline.coordinate,
radius: 20,
identifier: "\(i)")
self.locationManager.startMonitoring(for: region)
let circle = MKCircle(center: region.center, radius: region.radius)
self.mapa.add(circle)
}
let initialMessage = "In \(self.steps[0].distance) meters, \(self.steps[0].instructions) then in \(self.steps[1].distance) meters, \(self.steps[1].instructions)."
self.directionLabel.text = initialMessage
let speechUtterance = AVSpeechUtterance(string: initialMessage)
self.speechSynthesizer.speak(speechUtterance)
self.stepCounter += 1
}
}
}
extension NavigateVC: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
guard let currentLocation = locations.first else { return }
currentCoordinate = currentLocation.coordinate
mapa.userTrackingMode = .followWithHeading
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("ENTERED")
stepCounter += 1
if stepCounter < steps.count {
let currentStep = steps[stepCounter]
let message = "In \(currentStep.distance) meters, \(currentStep.instructions)"
directionLabel.text = message
let speechUtterance = AVSpeechUtterance(string: message)
speechSynthesizer.speak(speechUtterance)
} else {
let message = "Arrived at destination"
directionLabel.text = message
let speechUtterance = AVSpeechUtterance(string: message)
speechSynthesizer.speak(speechUtterance)
stepCounter = 0
locationManager.monitoredRegions.forEach({ self.locationManager.stopMonitoring(for: $0) })
}
}
}
extension NavigateVC: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.endEditing(true)
let localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
let region = MKCoordinateRegion(center: currentCoordinate, span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
localSearchRequest.region = region
let localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.start { (response, _) in
guard let response = response else { return }
guard let firstMapItem = response.mapItems.first else { return }
self.getDirections(to: firstMapItem)
}
}
}
extension NavigateVC: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .blue
renderer.lineWidth = 10
return renderer
}
if overlay is MKCircle {
let renderer = MKCircleRenderer(overlay: overlay)
renderer.strokeColor = .red
renderer.fillColor = .red
renderer.alpha = 0.5
return renderer
}
return MKOverlayRenderer()
}
}
Use this function
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
}
So that every time there is a change in serachbar text, this function will be called. You can reload the map whwnever required. I think this is what you are looking for.
I'm getting this error "Value of type 'UIGestureRecognizer' has no member 'numberOfTapsRequired' with my code as I'm adding double tap, I read many other posts on the subject and I can't find where is the problem. Can you spot what I'm doing wrong in the addDoubleTap function? This is the entire code
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, UIGestureRecognizerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var dropPinButton: UIButton!
#IBOutlet weak var centerMApButton: UIButton!
var pin: AnnotationPinn!
// variables that hold values for selected icon, to be used for displaying the pin
var dataReceived: String?
// udemy location manager couse
var locationManager = CLLocationManager()
let authorizationStatus = CLLocationManager.authorizationStatus()
let regionRadius: Double = 1000.0
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
configureLocationServices()
setCoordinates()
// addDoubleTap()
let latitude: Double = setCoordinates().lat //44.498955
let longitude: Double = setCoordinates().lon //11.327591
let title: String? = dataReceived
var subtitle: String? = dataReceived
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
// title may be to be taken from iconNames[indexpath.row]
pin = AnnotationPinn(title: "", subtitle: "", coordinate: coordinate)
}
func addDoubleTap() { //not finding numberOfTapsRequired
let doubleTap = UIGestureRecognizer(target: self, action: #selector(MapViewController.dropPin))
doubleTap.numberOfTapsRequired = 2
doubleTap.delegate = self
mapView.addGestureRecognizer(doubleTap)
}
func centerMapOnLocation() {
guard let coordinate2 = locationManager.location?.coordinate else {
return
}
let coordinateRegion = MKCoordinateRegionMakeWithDistance(coordinate2, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
//custom pin image , named: iconsImages[indexPath.row]
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: pin, reuseIdentifier: "strada chiusa")
//added if statement for displaying user location blue dot
if annotation is MKUserLocation{
return nil
} else {
annotationView.image = UIImage(named: dataReceived!) // here choose the image to load
let transform = CGAffineTransform(scaleX: 0.22, y: 0.22)
annotationView.transform = transform
return annotationView
}
}
// get coordinates into variables for the dropPin()
func setCoordinates() -> ( lat: Double, lon:Double) {
let location = locationManager.location?.coordinate
let lat:Double = (location?.latitude)!
let lon:Double = (location?.longitude)!
print(lat,lon)
return (lat, lon)
}
func dropPin() {
// print("3\(String(describing: dataReceived))")
mapView.addAnnotation(pin)
}
#IBAction func dropPinButton(_ sender: Any) {
performSegue(withIdentifier: "chooseIconSegue", sender: self)
}
#IBAction func centerMapButton(_ sender: Any) {
if authorizationStatus == .authorizedAlways || authorizationStatus == .authorizedWhenInUse{
centerMapOnLocation()
}
}
#IBAction func unwindHere(sender:UIStoryboardSegue) { // datas coming back
if let sourceViewController = sender.source as? IconsViewController {
// MyVariables.dataReceived = sourceViewController.dataPassed
dataReceived = sourceViewController.dataPassed
// title = sourceViewController.dataPassed
print(dataReceived!)
dropPin()
mapView.addAnnotation(pin)
}
}
func configureLocationServices() {
if authorizationStatus == .notDetermined{
locationManager.requestAlwaysAuthorization()
} else {
return
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
centerMapOnLocation()
}
}
extension MapViewController: CLLocationManagerDelegate{
}
UIGestureRecognizer doesn't have a property called numberOfTapsRequired, this is why you're getting the compilation error.
What you're after is UITapGestureRecognizer.
I've been having trouble figuring out how to pass a custom variable in a map pin to another view controller in Swift. I know that passing the coordinates, title, and subtitle are available when you addAnnotation. I would like to try and pass a custom variable but hidden. Is there such a thing? Below I am getting the users location, mapping it, dropping a pin of a couple locations nearby with annotations which goes to another view controller and passes just the title and subtitle. Any insight is greatly appreciated.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var mappedCity = String()
var mappedState = String()
var manager = CLLocationManager()
var annotation:MKAnnotation!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
var selectedAnnotation: MKPointAnnotation!
private var mapChangedFromUserInteraction = false
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = true
if CLLocationManager.locationServicesEnabled(){
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0]
let latitude = userLocation.coordinate.latitude
let longitude = userLocation.coordinate.longitude
let latDelta:CLLocationDegrees = 0.05
let lonDelta:CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
CLGeocoder().reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print(error)
}else {
if let p = placemarks?[0]{
let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""
self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)
self.parseJSON("\(locality)", state: "\(administrativeArea)")
}
}
}
self.manager.stopUpdatingLocation()
}
func parseJSON(city: String, state: String){
let passedCity = city
let passedState = state
let escapedCity = passedCity.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let escapedState = passedState.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let url = NSURL(string:"http://www.API.com/api.php?city=\(escapedCity)&stateAbv=\(escapedState)")!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (items, response, error) -> Void in
if error != nil {
print(error)
}else {
if let items = items {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(items, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if jsonResult.count > 0 {
if let datas = jsonResult["data"] as? NSArray{
for data in datas{
if let title = data["title"] as? String {
if let street = data["street"] as? String {
if let city = data["city"] as? String {
if let stateAbv = data["stateAbv"] as? String {
if let zip = data["zip"] as? String {
self.geoAddress("\(title)", street: "\(street)", city: "\(city)", state: "\(stateAbv)", zip: "\(zip)")
}
}
}
}
}
}
}
}
} catch{}
}
}
}
task.resume()
}
func geoAddress(title: String, street: String, city: String, state: String, zip: String){
let storeName = "\(title)"
let location = "\(street) \(city) \(state) \(zip)"
let geocoder = CLGeocoder();
geocoder.geocodeAddressString(location, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if (error != nil) {
print("Error \(error!)")
} else if let placemark = placemarks?[0] {
let coordinates:CLLocationCoordinate2D = placemark.location!.coordinate
let pointAnnotation:MKPointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = coordinates
pointAnnotation.title = storeName
pointAnnotation.subtitle = location
self.mapView.addAnnotation(pointAnnotation)
}
})
}
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
let view: UIView = self.mapView.subviews[0] as UIView
// Look through gesture recognizers to determine whether this region change is from user interaction
if let gestureRecognizers = view.gestureRecognizers {
for recognizer in gestureRecognizers {
if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
return true
}
}
}
return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if (mapChangedFromUserInteraction) {
// user changed map region
let center = mapView.centerCoordinate
let mapLatitude = center.latitude
let mapLongitude = center.longitude
let locationmove = CLLocation(latitude: mapLatitude, longitude: mapLongitude)
CLGeocoder().reverseGeocodeLocation(locationmove) { (placemarks, error) in
if (error != nil){
print(error)
}else {
if let p = placemarks?[0]{
let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""
self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)
self.parseJSON("\(locality)", state: "\(administrativeArea)")
}
}
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = false
pinView?.canShowCallout = true
pinView?.draggable = true
pinView?.pinTintColor = UIColor.greenColor()
let rightButton: AnyObject! = UIButton(type: UIButtonType.DetailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
selectedAnnotation = view.annotation as? MKPointAnnotation
performSegueWithIdentifier("Details", sender: self)
}
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.Ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "Details"){
let myDetails = segue.destinationViewController as! DetailViewController
myDetails.mytitle = selectedAnnotation.title
myDetails.mysubtitle = selectedAnnotation.subtitle
}
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
}
}
Subclass the "MKPointAnnotation" class and add your custom property in it.
class MyAnnotation : MKPointAnnotation {
var customProperty : String?
}
And you can use MyAnnotation instead of MKPointAnnotation. Like following
let pointAnnotation:MyAnnotation = MyAnnotation()
pointAnnotation.coordinate = coordinates
pointAnnotation.title = storeName
pointAnnotation.subtitle = location
pointAnnotation.customProperty = "your value"
self.mapView.addAnnotation(pointAnnotation)
I am using swift and I am working on a project, where I have to show a draggable map with changing location. and below the map I have subview and it have a button, on button click the subview will appear and on same button click I will disappear.
But the problem is sometime its working fine some time this view is go down and not coming on screen. and specially when I use button title change code.
class LocationMAP: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
#IBOutlet weak var locationLabel: UILabel!
#IBOutlet weak var selectAnyoneButton: UIButton!
#IBOutlet weak var selectingView: UIView!
var changingText:Bool = false
#IBOutlet weak var map: MKMapView!
var locationManger = CLLocationManager()
let geoCoder = CLGeocoder()
var myLocation: CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManger.delegate = self
locationManger.desiredAccuracy = kCLLocationAccuracyBest
locationManger.requestWhenInUseAuthorization()
locationManger.startUpdatingLocation()
if( CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways){
}
self.map.showsUserLocation = true
self.map.delegate = self
self.map.setUserTrackingMode(MKUserTrackingMode.Follow, animated: true)
let location = CLLocationCoordinate2DMake(20.59368, 78.96288)
let span = MKCoordinateSpanMake(0.2, 0.2)
_ = MKCoordinateRegionMake(location, span)
let annotation = MKPointAnnotation()
annotation.coordinate = (location)
selectAnyoneButton.setTitle("Submit", forState: .Normal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK:- MapView Delegates
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .Authorized, .AuthorizedWhenInUse:
manager.startUpdatingLocation()
self.map.showsUserLocation = true
default: break
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.myLocation = locations.last! as CLLocation
let userLocation:CLLocation = locations.last!
let long = userLocation.coordinate.longitude
let lat = userLocation.coordinate.latitude
print(long , lat)
// locationManger.stopUpdatingLocation()
self.map.centerCoordinate = myLocation.coordinate
let reg = MKCoordinateRegionMakeWithDistance(myLocation.coordinate, 1500, 1500)
self.map.setRegion(reg, animated: true)
geoCode(myLocation)
}
func geoCode(location : CLLocation!){
geoCoder.cancelGeocode()
self.locationManger.stopUpdatingLocation()
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemark, error) -> Void in
guard let placeMarks = placemark as [CLPlacemark]! else {
return
}
let loc: CLPlacemark = placeMarks[0]
let addressDict : [NSString:NSObject] = loc.addressDictionary as! [NSString: NSObject]
let addrList = addressDict["FormattedAddressLines"] as! [String]
let address = (addrList.joinWithSeparator(", "))
self.locationLabel.text = address
let lat = loc.location!.coordinate.latitude
let long = loc.location!.coordinate.longitude
print(lat , long)
SharedPreferenceManager.sharedInstance.userLatitude = lat
SharedPreferenceManager.sharedInstance.userLongitude = long
SharedPreferenceManager.sharedInstance.userAddress = address
})
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let location = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
geoCode(location)
self.map.removeAnnotations(mapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = map.centerCoordinate
annotation.title = "title"
annotation.subtitle = "subtitle"
self.map.addAnnotation(annotation)
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKPinAnnotationView()
if #available(iOS 9.0, *) {
annotationView.pinTintColor = UIColor.blueColor()
annotationView.center = CGPointMake(160, 200)
} else {
}
return annotationView
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState
newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if (newState == MKAnnotationViewDragState.Starting) {
view.dragState = MKAnnotationViewDragState.Dragging
}
else if (newState == MKAnnotationViewDragState.Ending || newState == MKAnnotationViewDragState.Canceling){
view.dragState = MKAnnotationViewDragState.None
}
}
//MARK:- Button Action Methods
#IBOutlet weak var downBtn: UILabel!
#IBAction func chooseButtonAction(sender: AnyObject) {
if (changingText == false) {
let newCenter:CGPoint = CGPointMake(selectingView.center.x, selectingView.center.y - 230)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.55)
selectingView.center = newCenter
UIView.commitAnimations()
selectAnyoneButton.setTitle("Select a service", forState: .Normal)
changingText = true
} else {
let newCenter:CGPoint = CGPointMake(selectingView.center.x, selectingView.center.y + 230)
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.55)
selectingView.center = newCenter
UIView.commitAnimations()
selectAnyoneButton.setTitle("Submit", forState: .Normal)
changingText = false
}
}
in button's action methods, add:
super.bringSubviewToFront(UIView)
towards the end.
I am assuming your view in question is a direct child of superview.