Reputation: 381
on the iPhone 3GS in the "Maps" app you can click the icon which usually shows your position twice and the blue dot gains what looks like a beam from a headlamp, basically showing you the direction you are facing on the map and rotating the image accordingly.
Is this option available using MapKit MapView ?
I'm know that I can get my heading with something like
- (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading {
// If the accuracy is valid, process the event.
if (newHeading.headingAccuracy > 0) {
CLLocationDirection theHeading = newHeading.magneticHeading;
...
}
}
but I don't know how to get that nice headlamp effect in Mapkit and there doesn't seem to be any documentation.
Any ideas?
Upvotes: 9
Views: 12077
Reputation: 4177
I could think of one method, though I have not implemented but may help you a bit.
didUpdateHeading
use the x and y values to calculate the angle of the direction.Please post your suggestions/changes for the above approach.
Upvotes: 2
Reputation: 651
Swift 3 implementation
mapView.userTrackingMode = MKUserTrackingMode.followWithHeading
Upvotes: 1
Reputation: 532
Adding user tracking mode also helps. I know I am late, but possibly a help to other developers like me :)
self.mapView.userTrackingMode = RMUserTrackingModeFollowWithHeading;
Upvotes: 6
Reputation: 2200
I found a solution:
I rotate the map using the available heading-information with
[mapView setTransform:CGAffineTransformMakeRotation(heading.magneticHeading * M_PI / -180.0)];
Therefore the "beam" always points to the top of the device. I now just display an ImageView on top of the map and change it's position in locationManager:didUpdateToLocation:fromLocation:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// scroll to new location
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 2000, 2000);
[self.mapView setRegion:region animated:YES];
// set position of "beam" to position of blue dot
self.headingAngleView.center = [self.mapView convertCoordinate:newLocation.coordinate toPointToView:self.view];
// slightly adjust position of beam
self.headingAngleView.frameTop -= self.headingAngleView.frameHeight/2 + 8;
}
Whereby frameTop and frameHeight are shortcuts for frame.origin.y and frame.size.height. It is not ideal and sometimes lacks a little bit when the dot changes it's position, but I'm happy with the solution b/c it works.
Have a look at my OpenSource framework MTLocation which does this all (and a lot of other cool Map-related stuff for you):
Upvotes: 4
Reputation: 1278
The rotating logic of the other answers are good, however relying on the location manager delegate methods won't result in a good solution. The "beam" image will rarely be in the same place as the blue dot and will bounce around a lot.
The best solution is to get a reference to the blue dot view, and add the "beam" image as a subview to it. I went with a beam image that was a square, with the beam up top and transparency all around it. Imagine the blue dot being in the center of the image.
// An MKMapViewDelegate method. Use this to get a reference to the blue dot annotation view as soon as it gets added
- (void)mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views {
for (MKAnnotationView *annotationView in views) {
// Get the user location view, check for all of your custom annotation view classes here
if (![annotationView isKindOfClass:[MKPinAnnotationView class]])
{
self.userLocationAnnotationView = annotationView;
gotUsersLocationView = YES;
}
}
}
// Adds the 'viewPortView' to the annotation view. Assumes we have a reference to the annotation view. Call this before you start listening to for heading events.
- (void)addViewportToUserLocationAnnotationView {
TTDASSERT(self.userLocationAnnotationView != nil);
if (self.userLocationAnnotationView == nil) {
// No reference to the view, can't do anything
return;
}
if (self.viewPortView == nil) {
self.viewPortView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"map_viewport.png"]] autorelease];
}
[self.userLocationAnnotationView addSubview:self.viewPortView];
[self.userLocationAnnotationView sendSubviewToBack:self.viewPortView];
self.viewPortView.frame = CGRectMake((-1 * self.viewPortView.frame.size.width/2) + self.userLocationAnnotationView.frame.size.width/2,
(-1 * self.viewPortView.frame.size.height/2) + self.userLocationAnnotationView.frame.size.height/2,
self.viewPortView.frame.size.width,
self.viewPortView.frame.size.height);
}
Upvotes: 3