Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable compass on MKMapView

I am using a MapView in my app to show some annotations. In iOS 7 a compass appears randomly on the map. I can't reproduce the error because it appears randomly but I want to disable it. Any ideas how to disable it?

Update: I found out is not appears randomly but on a specific gesture. When you use 2 fingers and slide one right and the other left.

like image 617
BlackM Avatar asked Oct 05 '13 09:10

BlackM


2 Answers

You can disable the compass easily on OSX 10.9 / iOS 9 and later with the showsCompass property.

Objective-C:

mapView.showsCompass = NO;

Swift:

mapView.showsCompass = false

Hiding the compass this way will not prevent a custom MKCompassButton from acting and appearing as normal.

On iOS 8 or earlier, your choices are:

  1. Suck it up and live with it.

  2. Use a hack, like:

    • position the map to hide the compass offscreen (credit goes to Alex Wien), or

    • walk the view hierarchy of the map to find the view representing the compass and remove it (credit goes to David Topolansky).

  3. If you're not rotating the map programatically and it hasn't already been rotated, disable rotation entirely, using

     mapView.rotateEnabled = NO;
    

The compass only shows up when the map is rotated, so by doing this you ensure that the compass is never triggered.

It's not clear to me why Apple waited so long to allow hiding the compass on iOS, and none of the options above are ideal. Pick whichever you think is the least bad in your case.

like image 125
Mark Amery Avatar answered Sep 20 '22 05:09

Mark Amery


I found a solution to your problem, using Mark Amery's idea about traversing the MKMapView instance subviews to find the compass, along with the use of gesture recognition to trigger the removal event.

To find the compass I printed out the description of the views and found that one of the views was an instance of MKCompassView, this was obviously the compass.

I have come up with the following code that should work for you. It checks for a rotation gesture, and then removes the view in method triggered by the gesture event.

I have tested this method and it works well for me:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIRotationGestureRecognizer *rotateGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)];

    [self.mapView addGestureRecognizer:rotateGesture];
}

-(void)rotate:(UIRotationGestureRecognizer *)gesture
{
    if ([gesture state] == UIGestureRecognizerStateBegan || [gesture state] == UIGestureRecognizerStateChanged) {
        // Gets array of subviews from the map view (MKMapView)
        NSArray *mapSubViews = self.mapView.subviews;

        for (UIView *view in mapSubViews) {
            // Checks if the view is of class MKCompassView
            if ([view isKindOfClass:NSClassFromString(@"MKCompassView")]) {
                // Removes view from mapView
                [view removeFromSuperview];
            }
        }
    }
}
like image 26
David Topolansky Avatar answered Sep 20 '22 05:09

David Topolansky