Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update map annotations on iOS 7 map camera rotation

I am trying to get it so that when you rotate an iOS 7 map that the annotations rotate along with the camera heading. Imagine I had pin annotations that must point to North at all times.

This would seem simple at first, there should be a MKMapViewDelegate for getting the camera rotation but there isn't.

I've tried using the map delegates to then query the map view's camera.heading object but firstly these delegates only seem to be called once before and once after a rotation gesture:

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

I also tried using KVO on the camera.heading object but this doesn't work and the camera object seems to be some kind of proxy object that only updates once the rotation gesture is complete.

My most successful method so far is to add a rotation gesture recogniser to calculate a rotation delta and use this with the camera heading reported at the beginning of the region change delegate. This works to a point but in OS 7 you can 'flick' your rotation gesture and it adds velocity which I can't seem to track. Is there any way to track the camera heading in real-time?

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
    heading = self.mapView.camera.heading;
}

- (void)rotationHandler:(UIRotationGestureRecognizer *)gesture
{
    if(gesture.state == UIGestureRecognizerStateChanged) {

        CGFloat headingDelta = (gesture.rotation * (180.0/M_PI) );
        headingDelta = fmod(headingDelta, 360.0);

        CGFloat newHeading = heading - headingDelta;

        [self updateCompassesWithHeading:actualHeading];        
    }
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    [self updateCompassesWithHeading:self.mapView.camera.heading];
}
like image 483
Electron Avatar asked Oct 21 '22 23:10

Electron


1 Answers

Apple does not give real time updates to any map information unfortunately. Your best bet is to set up a CADisplayLink and update whatever you need to when it changes. Something like this.

@property (nonatomic) CLLocationDirection *previousHeading;
@property (nonatomic, strong) CADisplayLink *displayLink;


- (void)setUpDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)];

    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}


- (void)displayLinkFired:(id)sender
{
   double difference = ABS(self.previousHeading - self.mapView.camera.heading);

   if (difference < .001)
       return;

   self.previousHeading = self.mapView.camera.heading;

   [self updateCompassesWithHeading:self.previousHeading];
}
like image 159
Ross Kimes Avatar answered Oct 26 '22 23:10

Ross Kimes