Search code examples
iosannotationsmapkitmkannotationmkannotationview

Hide or remove map annotations based on colour


I have a map loaded with pins of the 3 standard colours. These pins get coloured based on a value in an xml that is parsed and stored into an array.

I would like to add a segmented control with 2 buttons:

Button 1 to show only Green Pins.

and Button 2 to show only Red and Purple pins.

I have read about adding 3 different arrays for each pin colour and removing the array of pins but I want to maintain the one array. How would I do this if possible. I know how to implement a segmented control but I stumped on how to filter them on or off.

Heres my for loop: That creates the pins and assigns the 3 colours which works fine.

//Count the array of annotations and add them dynamically to the map.
for (int i = 0; i < locationArray.count; i++) {
    myAnnotation =[[MyAnnotation alloc] init];

    NSString *latString = [[locationArray objectAtIndex:i]xmlLat];
    NSString *lonString = [[locationArray objectAtIndex:i]xmlLon];

    type = [[locationArray objectAtIndex:i]xmlType];
    imageId = [[locationArray objectAtIndex:i]xmlImageId];
    address = [[locationArray objectAtIndex:i]xmlAddress];
    email = [[locationArray objectAtIndex:i]xmlEmail];
    phone = [[locationArray objectAtIndex:i]xmlPhone];
    live = [[locationArray objectAtIndex:i]xmlLive];
    form = [[locationArray objectAtIndex:i]xmlForm];
    name = [[locationArray objectAtIndex:i]xmlName];

    //Change the 0 to Active ticket and 1 to Closed 2 to False and 3 to Not Found and 4 to Other
    if ([live isEqualToString:@"0"]) {
        live = @"Active";
    }

    else if ([live isEqualToString:@"1"]){
        live = @"Closed";
    }

    else if([live isEqualToString:@"2"]){
        live = @"False";

    }

    else if ([live isEqualToString:@"3"]){
        live = @"Not Found";

    }

    else if ([live isEqualToString:@"4"]){
        live = @"Other";
    }


    double theLatitude = [latString doubleValue];
    double theLongtitude = [lonString doubleValue];

    userLocation.latitude=theLatitude;
    userLocation.longitude=theLongtitude;

    myAnnotation.coordinate=userLocation;
    myAnnotation.title=[NSString stringWithFormat:@"%@", imageId];
    myAnnotation.subtitle=[NSString stringWithFormat:@"%@", type];


    //Setting pin colours here based on value from XML
    if ([live isEqualToString:@"Active"]){
        myAnnotation.pinColor = MKPinAnnotationColorGreen;
    }else if ([live isEqualToString:@"Closed"]){
        myAnnotation.pinColor = MKPinAnnotationColorRed;
    }
    else if ([live isEqualToString:@"Not Found"]){
        myAnnotation.pinColor = MKPinAnnotationColorPurple;
    }
        [incidentsMap addAnnotation:myAnnotation];

    }

and heres my segmented control

-(IBAction)segmentedControl:(id)sender{

if (mapFilter.selectedSegmentIndex == 0) {
    NSLog(@"Active");
}

else if (mapFilter.selectedSegmentIndex == 1){
    NSLog(@"Closed");

//Remove Red and Purple Pins here from view when segmented control button button is    touched.........................

        }
else if (mapFilter.selectedSegmentIndex == 2){

    UIAlertView *mapSelector = [[UIAlertView alloc]initWithTitle:@"Select Map Type" message:@"Choose from 3 map views" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Default", @"Hybrid", @"Satelite", nil];
    [mapSelector show];

    }

}


Solution

  • The simplest approach is initially and whenever the filter criteria changes (eg. when the segmented control's value changes):

    1. Remove all annotations from the map. Use removeAnnotations (or removeAnnotation in some loop).
    2. Add only the ones that pass the filter criteria. You loop through the locationArray and only call addAnnotation for the ones that pass the filter.

    This may result in some flicker as annotations are removed and added again but is relatively easy to implement.


    Another alternative is to do the following (both initially and after the filter changes). Loop through the locationArray and:

    • if the item passes the filter and it is not already in the map's annotations array, add it to the map
    • if the item does not pass the filter and it is in the map's annotations array, remove it from the map

    However, this method requires that you have some unique property in your annotation object that can be used to implement the "is already in the map" existence check (using the coordinate is not recommended). You may need to add that unique property to the MyAnnotation class.

    Or, if you kept your own master array of all possible MyAnnotation objects, you could simply use containsObject to test if it is in the map's annotations array.