web-dev-qa-db-fra.com

Comment initialiser MKMapView avec un emplacement utilisateur donné?

Mon application connaît la position actuelle de l'utilisateur (CoreLocation.framework). Dès que l'utilisateur ouvre un nouveau MapView, son iPhone commence à rechercher à nouveau la position actuelle. Est-il possible d'ignorer cela ou de changer la première position d'utilisateur pour mkMapView?

Modifier:

Est-il possible d'écraser MKMapView et d'utiliser un autre LocationManager?

19
jantimon

Oui, il est possible d'avoir un objet de gestionnaire d'emplacement distinct et d'attribuer sa valeur à la mapview (BTW, j'utilise '=' ci-dessous comme préfixe de liste pour empêcher le formateur de code SO de se bouger).

= Dans votre UIViewController, gérez deux propriétés distinctes: l'une sur MKMapView et l'autre sur CLLocationManager

= Créez un fichier XIB avec la variable MKMapView et toute autre fenêtre chrome de votre choix. Connectez les prises aux propriétés du contrôleur. Assurez-vous que MKMapView ne suit PAS l'emplacement de l'utilisateur.

= Demandez à UIViewController d'implémenter le protocole CLLocationManagerDelegate - en particulier la méthode locationManager:didUpdateToLocation:fromLocation: qui sera appelée chaque fois qu'une nouvelle valeur d'emplacement est disponible. Nous allons définir le contrôleur en tant que délégué du gestionnaire d'emplacement.

= Dans la méthode loadView du viewController, chargez la NIB avec la MKMapView dans celui-ci. Pour donner votre avis à l'utilisateur, vous pouvez créer une spinner UIActivityIndicatorView et la définir sur startAnimating. Ensuite, vous commencez par:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
self.locationManager.distanceFilter = 10; // or whatever
[self.locationManager startUpdatingLocation];

= Dans locationManager:didUpdateToLocation:fromLocation:, vérifiez si l'événement a été mis à jour depuis les dernières N secondes. Ensuite, indiquez au responsable de la localisation d'arrêter la mise à jour, au spinner de cesser l'animation, récupérez les données lat/long et affectez-les à la vue cartographique avec une plage de vues et une région afin que le zoom et le centre soient au bon endroit.

= Maintenant, voici la partie la plus délicate: le "throbber" en marbre bleu est une caractéristique de l'emplacement de l'utilisateur de suivi de la carte. Vous devrez "simuler" momentanément jusqu'à ce que le véritable joueur entre en action (ou utilisez simplement un marqueur séparé pour l'emplacement actuel et maintenez vous-même sa position). Personnellement, j'irais avec le marbre bleu que l'utilisateur connaît. 

= Pour que cela s’affiche correctement au démarrage, vous devez créer un MKAnnotationView personnalisé avec uniquement le graphique en marbre bleu ajouté à l’emplacement renvoyé par le gestionnaire d’emplacement. Cela signifie qu’il faut prendre un instantané d’une carte avec l’emplacement affiché, puis effectuer un photoshopping de la bille bleue et l’utiliser comme image pour une vue d’annotation personnalisée.

= Si vous souhaitez qu'il suive activement la carte, vous pouvez activer le suivi de la localisation de la carte par l'utilisateur. Lorsqu'il récupère les données réelles, vous masquez le marqueur précédemment défini et laissez la vue de la carte se mettre à jour. L'autre option consiste à permettre au gestionnaire d'emplacement existant de continuer à recevoir des mises à jour toutes les secondes environ et de mettre à jour vous-même la position de l'annotation en marbre bleu.

= Pour permettre à l'utilisateur de localiser la mapview de faire la mise à jour, ajoutez à viewDidLoad:

[self.map.userLocation addObserver:self 
forKeyPath:@"location" 
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) 
context:NULL];
self.map.showsUserLocation = YES; // starts updating user location

= Implémenter observeValueForKeyPath. Il est appelé lorsque l'attribut location de la userlocation de la vue carte a une valeur:

-(void)observeValueForKeyPath:(NSString *)keyPath 
      ofObject:(id)object 
        change:(NSDictionary *)change 
       context:(void *)context 
{
     if ([self.map isUserLocationVisible]) {
         [self.locationManager stopUpdatingLocation];
         self.ownBlueMarble.hidden = YES;
     }
     // The current location is in self.map.userLocation.coordinate
}

= Pour éviter le délai d’échauffement lors de l’affichage de l’emplacement actuel, conservez une référence au viewController contenant la carte et le gestionnaire d’emplacement afin qu’il ne disparaisse pas (c’est un peu une mémoire volante, mais si vous le relâchez, attendre de nouveau jusqu'à ce que MapView charge les tuiles et soit prêt à partir). 

= Dans viewWillLoad, vous pouvez insérer le dernier emplacement connu dans l'annotation bluemarble personnalisée et l'afficher. Activez/désactivez le suivi userLocation et lorsque vous recevez la notification, le même problème de masquage masquer-l'annotation-afficher-le-vrai-marbre fonctionnera. Le propre responsable de la localisation de la carte s'affiche et lorsqu'il dispose des données, vous pouvez faire disparaître votre marqueur d'annotation.

= Vous pouvez vouloir implémenter la méthode viewWillDisappear de viewController et désactiver manuellement le suivi userLocation sur la vue map afin qu'il soit désactivé par défaut lors de la prochaine visualisation de la vue. Vous voudrez également obtenir la dernière userLocation connue et la sauvegarder pour le prochain démarrage. De cette façon, vous pouvez effectuer tout le positionnement en jonglant avec les marqueurs dans la méthode viewWillAppear sans avoir à vous soucier des interférences de userLocation tant que vous n'êtes pas prêt.

Bonne chance.

42
Ramin

Dans votre contrôleur:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    CLLocationCoordinate2D coord = {latitude: 37.423617, longitude: -122.220154};
    MKCoordinateSpan span = {latitudeDelta: 1, longitudeDelta: 1};
    MKCoordinateRegion region = {coord, span};
    [mapView setRegion:region];
}

Lorsque la carte apparaîtra, elle sera centrée près de Palo Alto

27
zakovyrya

Vous n'avez pas besoin d'utiliser un autre gestionnaire de lieux, vous pouvez ajouter les points souhaités sur la carte et les mettre à jour via la logique de votre choix.

Supposons que vous ayez une connexion de socket sur une voiture télécommandée et que cette voiture renvoie des données de socket contenant des informations de géolocalisation dans la charge utile. Vous pouvez analyser cette information et mettre à jour l'emplacement de la vignette sur votre carte en temps réel. La propriété "userLocation" n'est pas nécessaire pour cela, mais vous pouvez la montrer si vous le souhaitez.

L'emplacement de l'utilisateur est en lecture seule, vous pouvez l'utiliser ou non. Cela ne signifie pas que vous avez besoin d'un autre gestionnaire d'emplacement pour faire tout ce que vous pourriez avoir besoin de faire. On dirait que votre application n'a pas vraiment besoin de cette fonctionnalité, mais je peux mal comprendre votre question.

0
slf

Essayez de définir la propriété showUserLocation sur false lors de l’initialisation, puis restaurez la region que la carte avait précédemment (vous devrez évidemment la stocker avant la destruction de la carte précédente).

C'est ce que tu voulais?

0
Nick Bedford