Penser à Swift

Avez-vous remarqué le nombre d’applications pouvant être réunies dans lesquelles nous sommes situés, indiquez des endroits intéressants proches, Mark itinéraires …? Dans cet article, je vais expliquer comment une application des cartes et des itinéraires est construite avec MapKit.

Mais qu’est-ce que mapkit? MapKit est un cadre Apple qui basse son fonctionnement sur les données de l’API et de la carte Apple, de sorte que les cartes puissent être facilement ajoutées aux applications développées, dans ce cas, pour iOS.

un peu de swift

Ce projet peut être trouvé complet dans github.

Conception d’interface

Ce projet comprendra essentiellement un composant MKAPView, qui nous montrera la carte, que nous allons ajouter Différents composants selon les fonctionnalités que nous souhaitons ajouter à l’application. De plus, dans ce projet, tout cela se fera via du code, sans utiliser de storyboards ou de fichiers .xib.

Création du projet

Pour travailler sans scénario lors de l’établissement d’un projet dans Xcode 11, nous devons prendre un projet Quelques étapes après l’avoir créée:

  • Supprimons le fichier principal.storyboard.
  • sur l’onglet Général, nous allons au sélecteur d’interface principal et supprimez-le, laissant le champ vide.
« f349c9b229″>
<9b5b762e33 ">
Vous devez supprimer le champ principal et laisser le champ blanc.

  • Enfin, sur l’onglet Info, nous allons à l’application Scène Manifest > Configuration de la scène > Rôle de la session d’application > Item 0 (Configuration par défaut) et supprimez le champ Nom du storyboard.
Efface du champ Nom du scénario dans le fichier info.plist.

Comme maintenant, nous n’appellerons pas la carte principale pour démarrer le projet, nous allons au fichier ScendineEgate.swift et dans la fonction Scène (_ Scène: UISCENE, Session WillConnectTo: UISCENESESSION, Options ConnexionOPTIONS: UISCENE. connectoptions) et remplacer son contenu par le code suivant:

guard let windowScene = (scene as? UIWindowScene) else { return }window = UIWindow(frame: UIScreen.main.bounds)let viewController = ViewController()window?.rootViewController = viewControllerwindow?.makeKeyAndVisible()window?.windowScene = windowScene

Ajouter une carte à notre

à Ajoutez une carte à l’écran, il suffit de créer une instance de MKMAPView et de l’ajouter à la vue d’écran. Pour ce faire, dans la classe ViewController, nous devons tout d’abord importer la bibliothèque Mapkit, puis nous créons une instance de MKMAPView et le présentez-la:

import UIKitimport MapKitclass ViewController: UIViewController { private let mapView = MKMapView(frame: .zero) override func viewDidLoad() { super.viewDidLoad() layoutUI() } private func layoutUI() { mapView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(mapView) NSLayoutConstraint.activate() }}

Si nous exécutons l’application, nous pouvons voir une carte approximative à l’écran de l’endroit où nous sommes localisés.

<

Présentation de la carte.

Pour nous montrer exactement, nous devons utiliser La classe CllouerManager, qui indique qu’Apple indique, vous permet de démarrer et de terminer l’envoi d’événements de localisation à notre application:

  • détecte les modifications apportées à la position de l’utilisateur.
  • Voir les modifications Dans l’adresse de la boussole.
  • surveiller les régions d’intérêt.
  • détecte la position des balises voisines.

autorisations

N’oubliez pas que pour utiliser les fonctions de localisation, avant de devoir demander la permission Nom d’utilisateur. Pour cela, nous ajoutons dans le fichier info.plist, une série de paramètres (comme je l’ai également montré à utiliser des notifications):

  • Confidentialité – Emplacement Toujours et lors de l’utilisation Description d’utilisation
  • Confidentialité – Emplacement Toisy Utilisation Description
  • Confidentialité – Localisation Lors de l’utilisation Utilisation Description

Ce que nous donnons comme valeur le message que nous souhaitons montrer à l’utilisateur à demander Pour la permission (dans cet exemple, « Autoriser l’accès à l’emplacement afin d’utiliser cette application. »).

<4807922270">

Modification de l’info.Plist Fichier de la demande d’autorisation.

Une fois l’info fichier.plist, nous allons Pour effectuer la vérification de l’application, d’abord, si les services de localisation sont activés, puis, si l’année USUAR a donné une autorisation et quel type d’autorisation.Ce que nous faisons en premier lieu consiste à créer une instance de la classe CllouerManager:

private let locationManager = CLLocationManager()

et ensuite, nous créons la checkloctionervice méthode, dans celle que nous vérifierons si les services de localisation sont activés sur l’appareil et, dans l’affirmative, nous établirons le délégué (délégué) de cette classe comme indiqué dans la documentation et nous indiquerons avec quelle précision nous voulons travailler le Emplacement:

private func checkLocationServices() { guard CLLocationManager.locationServicesEnabled() else { // Here we must tell user how to turn on location on device return } locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest}

Cette fonction l’appellera à partir de la méthode ViewDidLoad. Bien que nous établissons le délégué, nous avons adopté quelques méthodes de ce délégué qui nous permettront de savoir si cela change d’autorisation donnée par l’utilisateur sur l’utilisation de l’emplacement (EmplacementManager (_: DidChangeAtorization :)) et lorsque l’emplacement de l’utilisateur (EmplacementManager (_: DidupdaTelocations :)) (Nous le faisons dans une extension de la classe ViewController pour avoir le code organisé):

<23E4B5D29A ">

Nous pouvons maintenant continuer à remplir la classe ViewController en ajoutant la méthode qui ressemblera si l’application a la permission et quel type d’autorisation utiliser l’emplacement. Dans cette méthode, ce que nous faisons, c’est appeler la méthode d’autorisationStatus de la classe CllouerManager et vérifier quelle valeur nous obtenons:

private func checkAuthorizationForLocation() { switch CLLocationManager.authorizationStatus() { case .authorizedWhenInUse, .authorizedAlways: mapView.showsUserLocation = true locationManager.startUpdatingLocation() break case .denied: // Here we must tell user how to turn on location on device break case .notDetermined: locationManager.requestWhenInUseAuthorization() case .restricted: // Here we must tell user that the app is not authorize to use location services break @unknown default: break }}

comme vous peut voir, il existe différentes possibilités concernant l’autorisation de l’utilisation de l’emplacement:

  • AuthorisizeinUtilisée. L’utilisateur a autorisé l’application à démarrer les services d’emplacement lorsqu’il est utilisé.
  • Autorisé. L’utilisateur a autorisé l’application à démarrer les services de localisation à tout moment.
  • refusé. L’utilisateur a rejeté l’utilisation des services d’emplacement pour l’application ou est désactivée dans le monde entier dans les paramètres.
  • Notdéterminé. L’utilisateur n’a pas choisi si l’application peut utiliser des services de localisation.
  • restreint. L’application n’est pas autorisée à utiliser les services de localisation.

Cette fonction, checkauthorizeforlocation, nous l’appellerons à deux points:

  • dans les services de checklocations () Après avoir établi le délégué, après avoir entré la demande.
  • sur la méthode EmplacementManager (_: DidChangeAuthorization :), au cas où l’autorisation de l’utilisateur change lors de l’utilisation de l’application.
private func checkLocationServices() { guard CLLocationManager.locationServicesEnabled() else { // Here we must tell user how to turn on location on device return } locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest checkAuthorizationForLocation()}func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { checkAuthorizationForLocation()}

Si nous exécutons maintenant l’application, nous verrons comment il affiche une alerte demandant une autorisation d’utiliser des services de localisation.

= « 1651a32b04″>
.

Une fois que nous avons autorisé l’application à utiliser les services de localisation, ce que nous avons à faire est de vous dire que vous pouvez activer le suivi de la position de l’appareil. Pour ce faire, dans la méthode checkauthorizeforLocation () et dans les cas qui permettent une utilisation, nous ajoutons le code suivant:

case .authorizedWhenInUse, .authorizedAlways: mapView.showsUserLocation = true centerViewOnUser() locationManager.startUpdatingLocation() break

lo Que nous faisons ici, c’est dire que l’instance de mkmapview doit afficher la position de l’utilisateur (MapView.ShowsuserLocation = true), qui concentre la vue sur l’utilisateur (méthode que nous allons créer maintenant) et que la mise à jour de l’emplacement est activée.

Montrez notre position sur la carte

La méthode Centerviewonuer (), ce qu’elle est déterminée à partir de l’emplacement de l’utilisateur, l’établissement d’une région rectangulaire centrée est un point. Pour cela, nous utilisons mkcoordinateegion.

private let rangeInMeters: Double = 10000private func centerViewOnUser() { guard let location = locationManager.location?.coordinate else { return } let coordinateRegion = MKCoordinateRegion.init(center: location, latitudinalMeters: rangeInMeters, longitudinalMeters: rangeInMeters) mapView.setRegion(coordinateRegion, animated: true)}

ici, d’abord nous nous assurons d’avoir la position de l’utilisateur. Ensuite, nous établissons une région de 10 x 10 km concentrée sur l’utilisateur. Enfin, nous établissons cette région sur la carte. De cette façon, nous obtenons l’image suivante sur l’appareil.

Enfin, pour pouvoir activer la position de l’utilisateur sur la carte, dans la méthode EmplacementManager (_: DidupdaTelocations 🙂 Nous faisons quelque chose comme ce que nous avons fait pour centrer la vue L’utilisateur:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: ) { guard let location = locations.last else { return } let coordinateRegion = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: rangeInMeters, longitudinalMeters: rangeInMeters) mapView.setRegion(coordinateRegion, animated: true)}

Mais dans ce cas, l’emplacement que nous obtenons de la dernière valeur de la liste des emplacements qui renvoie La méthode.

Sélectionnez le type de carte

La carte que nous voyons par défaut lorsque l’application est activée est le type standard. MapKit vous permet d’afficher différents types de cartes en modifiant la valeur du paramètre MapType de l’instance MkmapView:

  • standard. Une carte des rues qui montre la position de toutes les routes et des noms de route.
  • satellite. Images satellitaires de la zone.
  • hybride. Une image satellite de la zone avec des informations sur les routes et le nom (dans une couche au-dessus de la carte).
  • satelliteflyover.Une image satellite de la zone avec des données de la zone (où elles sont disponibles).
  • hybridflyover. Une image satellite hybride avec des données de la zone (où elles sont disponibles).
  • MuTanTandard. Une carte de rue où nos données sont surlignées sur les détails de la carte.

Dans ce cas, nous n’utiliserons que trois types de cartes: standard, satellite et hybride.

La sélection du type de carte que nous souhaitons afficher dans l’application Nous l’utiliserons à l’aide d’un bouton avec un menu déroulant, qui peut être téléchargé comme un package SWIFT (Fabbutton). Pour cela, nous suivons ces étapes:

  • du menu Fichier Xcode > Swift Package > Ajouter Forfait Dépendance … Nous ajoutons le composant Fabbutton. L’URL est: https://github.com/raulferrerdev/FABButton.git
  • Suivant, nous créons une instance de la et de sa configuration (les icônes utilisées sont déjà incluses dans le projet):
private let mapTypeButton = FABView(buttonImage: UIImage(named: "earth")override func viewDidLoad() { super.viewDidLoad() ... configureMapTypeButton() ...} private func configureMapTypeButton() { mapTypeButton.delegate = self mapTypeButton.addSecondaryButtonWith(image: UIImage(named: "map")!, labelTitle: "Standard", action: { self.mapView.mapType = .mutedStandard }) mapTypeButton.addSecondaryButtonWith(image: UIImage(named: "satellite")!, labelTitle: "Satellite", action: { self.mapView.mapType = .satellite }) mapTypeButton.addSecondaryButtonWith(image: UIImage(named: "hybrid")!, labelTitle: "Hybrid", action: { self.mapView.mapType = .hybrid }) mapTypeButton.setFABButton()}

  • Comme vous pouvez le constater, nous avons établi le délégué pour le type FABVIEW, nous devons donc faire le Classe ViewController est conforme à ce protocole. Pour que nous ajoutons l’extension suivante au projet:
« 1e22bdaca »>

  • enfin, dans la méthode LayoutUI Nous ajoutons le bouton à la vue et indiquons votre message:
<4b379ff582 ">

Si nous exécutons la demande, nous pouvons Vérifiez que nous pouvons changer de type de carte:

Afficher les adresses

Ce que nous allons faire est de montrer l’adresse d’un point sur la carte (le centre) sur l’écran, que nous obtiendrons à travers la classe de Cllocation. Pour cela, nous créons une fonction GetCenterLocation, à laquelle nous passons l’instance de MKMAPView que nous avons et nous reviendrons les coordonnées du point central:

func getCenterLocation(for mapView: MKMapView) -> CLLocation { let coordinates = mapView.centerCoordinate return CLLocation(latitude: coordinates.latitude, longitude: coordinates.longitude)}

Pour savoir exactement quel est le centre de la carte, nous allons passer une icône au centre de la carte. Nous ferons cela avec un élément UiImageView, avec l’image d’une épingle (nous recevrons des symboles SF d’Apple).

private let pointer = UIImageView(image: UIImage(systemName: "mappin"))private func layoutUI() { ... pointer.translatesAutoresizingMaskIntoConstraints = false pointer.tintColor = .red ... view.addSubview(pointer) NSLayoutConstraint.activate()}

Pour le bas de la broche exactement au centre de la carte, nous déplions cette icône la moitié de sa hauteur (-14.5px).

En plus, pour montrer l’adresse que nous allons placer une Étiquetez en haut de l’écran, comme indiqué dans la conception. Pour cela, nous créons une instance d’Uilabel, nous la configurons et se tiendrons à l’écran:

private let addressLabel = UILabel(frame: .zero)private func configureAddressLabel() { addressLabel.translatesAutoresizingMaskIntoConstraints = false addressLabel.font = .systemFont(ofSize: 18.0, weight: .medium) addressLabel.textColor = .darkText addressLabel.textAlignment = .center addressLabel.backgroundColor = .init(white: 1, alpha: 0.75) addressLabel.layer.cornerRadius = 5.0 addressLabel.clipsToBounds = true}private func layoutUI() { ... view.addSubview(addressLabel) NSLayoutConstraint.activate()}

Obtention de l’adresse

Pour obtenir l’adresse d’un lieu de vos coordonnées, nous utiliserons la classe Cligeocoder, qui indique que la documentation Apple, vous permettra d’obtenir de la longueur et de la latitude d’un point une représentation «conviviale». À partir de cet emplacement:

La classe Cligeododer fournit des services destinés à la conversion entre une coordonnée (spécifiée comme une latitude et une longitude) et la représentation conviviale de cette coordonnée À une représentation conviviale de la coordonnée se compose généralement des informations de rue, de ville, d’état et de pays correspondant à l’emplacement donné, mais elle peut également contenir au point d’intérêt, à un point de repère ou à d’autres informations d’identification pertinentes.

Apple Documentation (CLGEOCODER)

Pour connaître les coordonnées du point central de la carte, nous implémentons le délégué MKMAPView et la méthode qui collecte chaque fois que vous déplacez la carte. .

private let geoCoder = CLGeocoder()private var previousLocation: CLLocation?extension ViewController: MKMapViewDelegate { func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { let center = getCenterLocation(for: mapView) guard let previousLocation = self.previousLocation, center.distance(from: previousLocation) > 25 else { return } self.previousLocation = center geoCoder.reverseGeocodeLocation(center) { (placemarks, error) in guard let self = self else { return } if let _ = error { // Show alert for the user return } guard let placemark = placemarks?.first else { // Show alert for the user return } let streetNumber = placemark.subThoroughfare ?? "" let streetName = placemark.thoroughfare ?? "" DispatchQueue.main.async { self.addressLabel.text = "\(streetNumber) \(streetName)" } } }}

Dans cette méthode, nous faisons ce qui suit:

  • Tout d’abord nous obtenons les coordonnées du centre de la carte (grâce à la fonction GetCenterLocation, que nous avons déjà vue précédemment).
  • La prochaine étape consiste à savoir s’il y a une position préalable (répartition de la précédente, que nous avons instanciée à la Début) et, dans ce cas, vérifiez que la différence de distance à la nouvelle position est supérieure, dans ce cas, 25 m. Si ces conditions sont remplies, la valeur des nouvelles coordonnées est attribuée à la variable de répartition de la précédente.
  • Ensuite, nous prenons une instance de la fonction CLGEOCODER et appelons la méthode ReverseCoDelocation, que nous passons les coordonnées du centre de l’écran.
  • Cette fonction renvoie un bloc avec deux paramètres:
<1fde5def94 ">

  • de ces deux valeurs, nous vérifions qu’aucune erreur n’a eu lieu et qui a renvoyé une position. Un objet Clapemark stocke des données faisant référence à certaines la latitude et la longitude (telles que, par exemple, le pays, l’État, la ville et la direction de la rue, des points d’intérêt et des données géographiquement associées).
  • de ces informations nous intéressons à deux paramètres: la voie de circulation (qui est l’adresse de rue associée à la position indiquée) et à la sous-thorhoroughfare (qui donne des informations supplémentaires sur cette adresse).
  • enfin , et dans le fil principal, nous ajoutons ces informations à l’étiquette.

Définir des itinéraires

Maintenant, ce que nous avons laissé à faire dans ce projet consiste à mettre en place un système d’itinéraire. C’est-à-dire d’un point d’origine et d’une autre de destination, établir les itinéraires optimaux pour la route.

Ceci peut le faire facilement grâce à MapKit. Dans ce cas, nous utiliserons la classe MKDirections.Request, qui nous permettra d’établir une demande (demande) dans laquelle nous indiquons le point d’origine, la destination, le type de transport, si nous voulons que les voies alternatives soient affichées …

  • var source: mkmapitem ?. Est le point de départ des itinéraires.
  • Var destination: mkmapitem?. C’est la destination de rencontres des itinéraires.
  • var transporttype: mkdirectionsTransporttype. C’est le type de transport qui s’applique pour calculer les itinéraires. Il peut s’agir de l’automobile, de la marche, du transit ou de tout.
  • var requêtesAaterout: Bool. Indique si nous voulons des itinéraires alternatifs, au cas où ils seront disponibles.
  • VAR DIPERRÉTATE: DATE ?. C’est la date de départ du voyage.
  • Var ArrivageDate: date? C’est la date d’arrivée du voyage.

Ce que nous faisons est de créer une méthode qui retournera un objet du type mkdirections.Request Type:

func createRequest() -> MKDirections.Request? { guard let coordinate = locationManager.location?.coordinate else { return nil } let destinationCoordinate = getCenterLocation(for: mapView).coordinate let origin = MKPlacemark(coordinate: coordinate) let destination = MKPlacemark(coordinate: destinationCoordinate) let request = MKDirections.Request() request.source = MKMapItem(placemark: origin) request.destination = MKMapItem(placemark: destination) request.transportType = .automobile request.requestsAlternateRoutes = true return request}

Dans cette méthode, nous obtenons d’abord les coordonnées du point central de l’écran. Ensuite, nous créons des objets de type Mkplacemark avec les coordonnées d’origine (le point où nous sommes) et de la destination. Enfin, nous créons une instance de type mkdirections.Request avec indiquant l’origine, la destination, le type de transport (automobile) et que nous voulons des itinéraires alternatifs.

Pour dessiner la route, je dois le faire est de démarrer un objet supérieur mkdirections avec la demande (demande) que nous avons créée. Comme indiqué par la documentation d’Apple, cet objet calcule les adresses et les informations de temps de traçage basées sur les informations de route que vous fournissez.

Par conséquent, nous allons créer une méthode à partir de la création d’une demande (demande), obtenir un Objet de type mkdirection et représentent les itinéraires:

dans cette méthode, une fois que l’objet a été obtenu, des mkdirections, nous utilisons le FUNC Calculer la méthode, qui renvoie un type d’objet MKDirections. Réponse et une éventuelle erreur:

« 9cbd6a5c58″>

Nous vérifions que la réponse est valide et nous prenons les paramètres des itinéraires, qui correspond à une liste d’objets de type MKRoute représentant les itinéraires entre les points source et de destination.

Si vous regardez la documentation Apple, l’objet MKROUTE a un paramètre appelé Polyline. , qui contient le chemin de la route. Pour représenter cette mise en page, ce que nous avons fait est de transmettre ce paramètre à la méthode addoverlay (_ superposition: mkoverlay) de l’objet MkmapView. Ensuite, nous modifions la partie visible de la carte à l’aide de la méthode SETVISIBLEMAPRect (_ Mapret: mkmaprect, animé animate: bool).

De plus, nous devons ajouter une méthode du protocole MKAPViewelegate afin que les itinéraires soient tirés. (dessinez-les en couleur vert et une épaisseur de 5px):

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { let renderer = MKPolylineRenderer(overlay: overlay as! MKPolyline) renderer.strokeColor = .green renderer.lineWidth = 5 return renderer}

maintenant, ce dont nous avons besoin, c’est ajouter un bouton nous permet de commencer le calcul de l’itinéraire. À partir de la conception de l’interface, nous avons montré au début, nous ajoutons et configurons un élément UIBUTTON, que nous ajouterons comme cible la méthode des tiroirs ():

private let startButton = UIButton(frame: .zero) override func viewDidLoad() { super.viewDidLoad() ... configureStartButton()}private func configureStartButton() { startButton.translatesAutoresizingMaskIntoConstraints = false startButton.setTitle("Start", for: .normal) startButton.backgroundColor = .systemRed startButton.setTitleColor(.white, for: .normal) startButton.titleLabel?.font = .systemFont(ofSize: 18.0, weight: .bold) startButton.layer.cornerRadius = 5.0 startButton.clipsToBounds = true startButton.addTarget(self, action: #selector(drawRoutes), for: .touchUpInside)}private func layoutUI() { ... view.addSubview(startButton) ... NSLayoutConstraint.activate()}extension ViewController: MKMapViewDelegate { ... func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { let renderer = MKPolylineRenderer(overlay: overlay as! MKPolyline) renderer.strokeColor = .green renderer.lineWidth = 5 return renderer }}

Conclusions

La bibliothèque Mapkit d’Apple vous permet de développer dans un Simple Way une application qui affiche des cartes, montrez notre position sur la carte, montrez-vous des instructions à partir d’un point sélectionné sur la carte et les itinéraires pour atteindre cette adresse.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *