选择注释引脚时更改引脚颜色

Posted

技术标签:

【中文标题】选择注释引脚时更改引脚颜色【英文标题】:Changing pin color when selecting annotation pin 【发布时间】:2013-09-10 00:48:26 【问题描述】:

我的应用程序是一个地图视图,用户可以在其中输入一个地址,该地址将在地图上为总部放置一个紫色图钉。其次,用户可以输入任何地址,这将在地图上放置一个红色的大头针。我希望能够将红色引脚的引脚颜色更改为红色、绿色或紫色。

我偶然发现了一个教程,该教程允许用户选择注释引脚并通过显示模式视图来更改其引脚颜色。我仔细按照教程进行操作,但由于某种原因,它无法正常工作。显示了引脚选择的模态视图,但选择引脚颜色时,地图视图上的引脚颜色不会更新。此外,我不想使用“png”图像来显示自定义引脚,而是使用内置的标准引脚(因为这就是我所需要的)。如何调整下面的代码以实现此目的?我添加了我的整个代码。

FieldMapController.m

#import "FieldMapController.h"
#import "CustomAnnotation.h"
#define HQ_latitude @"headquarters_latitude"
#define HQ_longitude @"headquarters_longitude"
#define HQ_coordinates @"headquarters_coordinates"
#import "PinSelectionViewController.h"

@interface FieldMapController ()

@end

@implementation FieldMapController 

@synthesize mapView;
@synthesize searchBar;
@synthesize geocoder = _geocoder;



- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


//ACCESS SAVED DATA FROM NSUSERDEFAULTS
-(void)viewWillAppear:(BOOL)animated

    NSUserDefaults *uDefaults = [NSUserDefaults standardUserDefaults];
    if ([uDefaults boolForKey:@"headquarters_coordinates"])
    

        CLLocationCoordinate2D savedCoordinate;
        savedCoordinate.latitude = [uDefaults doubleForKey:@"headquarters_latitude"];
        savedCoordinate.longitude = [uDefaults doubleForKey:@"headquarters_longitude"];

        NSLog(@"Your HQ is at coordinates %f and %f",savedCoordinate.latitude, savedCoordinate.longitude);

        CustomAnnotation *annHq =[[CustomAnnotation alloc] init];
        annHq.title=@"HQ";
        annHq.subtitle=@"";
        annHq.coordinate= savedCoordinate;
        [mapView addAnnotation:annHq];

        MKCoordinateRegion viewRegion = 0.0, 0.0, 0.0, 0.0;
        viewRegion.center.latitude = savedCoordinate.latitude;
        viewRegion.center.longitude = savedCoordinate.longitude;
        viewRegion.span.longitudeDelta = 0.5f;
        viewRegion.span.latitudeDelta = 0.5f;
        [self.mapView setRegion:viewRegion animated:YES];
        [self.mapView setDelegate:self];


    




- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.mapView.delegate = self;
    self.searchBar.delegate = self;


    //SEARCH BAR TOOLBAR WITH "DONE" AND "CANCEL" BUTTON
    UIToolbar* searchToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
    searchToolbar.barStyle = UIBarStyleBlackTranslucent;
    searchToolbar.items = [NSArray arrayWithObjects:
                           [[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStyleBordered target:self action:@selector(cancelSearchBar)],
                           [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                           nil];
    [searchToolbar sizeToFit];
    searchBar.inputAccessoryView = searchToolbar;




//WHEN PUSHING THE "CANCEL" BUTTON IN THE SEARCH BAR
-(void)cancelSearchBar

    [searchBar resignFirstResponder];
    searchBar.text = @"";



//PREPARE SEGUE FOR THE PIN SELECTOR VIEW
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if([segue.identifier isEqualToString:@"ShowPinChoicesSegue"])
    
        PinSelectionViewController *pinVC = [segue destinationViewController];

        CustomAnnotation *selectedAnnotation = (CustomAnnotation *)sender;
        pinVC.currentPinType = selectedAnnotation.pinType;
        pinVC.delegate = self;
    


//WHAT HAPPENS WHEN THE "SEARCH" BUTTON AT THE SEARCH BAR KEYBOARD IS TAPPED
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar


    //Forward Geocoder
    if (!self.geocoder)
    
        self.geocoder = [[CLGeocoder alloc] init];
    

    NSString *address = [NSString stringWithFormat:@"%@", self.searchBar.text];

    [self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) 
        if ([placemarks count] > 0)
        
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            CLLocation *location = placemark.location;
            CLLocationCoordinate2D coordinate = location.coordinate;

            //Display Coordinates in Console
            NSLog (@"%f %f", coordinate.latitude, coordinate.longitude);

            MKCoordinateRegion region;
            MKCoordinateSpan span;
            span.latitudeDelta = 0.01;
            span.longitudeDelta = 0.01;
            region.span = span;
            region.center = coordinate;

            //Create Annotation with Callout Bubble that displays "No Information"
            MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
            [annotation setCoordinate:coordinate];
            [annotation setTitle:@"No Information"];
            [[self mapView] addAnnotation:annotation];
            [self.mapView setRegion:region animated:TRUE];
            [self.mapView regionThatFits:region];

            //Dismiss the Search Bar Keyboard
            [self.searchBar resignFirstResponder];

            //Delete text in Search Bar
            self.searchBar.text = @"";

        
    ];



//CUSTOM ANNOTATION VIEW
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation


    if ([annotation isKindOfClass:[MKUserLocation class]])
    
        return nil;
    

    if ([annotation isKindOfClass:[CustomAnnotation class]])

    

        MKPinAnnotationView *annotationView =
            (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:((CustomAnnotation *)annotation).annotationViewImageName];
        if(annotationView == nil)
        
            MKPinAnnotationView *customPinView =

            [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:((CustomAnnotation *)annotation).annotationViewImageName];

            if([[customPinView.annotation title] isEqualToString:@"HQ"])
            

                //The pin for the HQ should be purple
                customPinView.pinColor = MKPinAnnotationColorPurple;

            
            else 
            
                //All other new pins should be "red" by default
                customPinView.image = [UIImage imageNamed:((CustomAnnotation *)annotation).annotationViewImageName];

            

            customPinView.canShowCallout = YES;
            customPinView.animatesDrop = YES;

            //Right Callout Accessory Button
            UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            customPinView.rightCalloutAccessoryView = rightButton;

            return customPinView;
        
        else
        
            annotationView.annotation = annotation;
        
        return annotationView;
    

    return nil;



//SHOW ACCESSORY VIEW WHEN BUTTON ON CALLOUT BUBBLE IS TAPPED
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control

    if (![view.annotation isKindOfClass:[CustomAnnotation class]])
        return;
    CustomAnnotation *customAnnotation = (CustomAnnotation *)view.annotation;

    if (control.tag == 0)
    
        [self performSegueWithIdentifier:@"ShowPinChoicesSegue" sender:customAnnotation];
    
    else
    
        [self onRightCalloutAccessoryViewTouched:control];

    




-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view


    if(![view.annotation isKindOfClass:[CustomAnnotation class]])
        return;
    if (!view.rightCalloutAccessoryView)
    
        UIButton *rightViewButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 48.0, 32.0)];
        [rightViewButton addTarget:self action:@selector(onRightCalloutAccessoryViewtouched:) forControlEvents:UIControlEventTouchUpInside];
        rightViewButton.tag = 1;
        view.rightCalloutAccessoryView = rightViewButton;
    


-(void)onRightCalloutAccessoryViewTouched:(id)sender

    CustomAnnotation *selectedAnnotation = (CustomAnnotation *)[mapView.selectedAnnotations objectAtIndex:0];
    [self performSegueWithIdentifier:@"ShowPinChoicesSegue" sender:selectedAnnotation];



- (void)viewDidUnload

    self.mapView = nil;
    self.searchBar = nil;



- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];


//BUTTON TO SELECT NEW HQ
- (IBAction)selectHq:(UIBarButtonItem *)sender


    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Select Headquarters"
                                                    message:@"Enter Address"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"Ok", nil];


    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    [[alert textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeDefault];

    [alert show];



//REMOVING ALL PINS EXCEPT USER LOCATION
- (IBAction)resetPins:(UIBarButtonItem *)sender


    id userLocation = [mapView userLocation];
    NSMutableArray *pins = [[NSMutableArray alloc] initWithArray:[mapView annotations]];
    if ( userLocation != nil )
    
        [pins removeObject:userLocation]; //avoid removing user location
    

    [mapView removeAnnotations:pins];
    pins = nil;
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_coordinates];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_longitude];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:HQ_latitude];


//ALERT VIEW TO ENTER ADDRESS OF HQ
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex


    if (buttonIndex != alertView.cancelButtonIndex)

    

        UITextField *field = [alertView textFieldAtIndex:0];
        field.placeholder = @"Enter HQ Address";

        if (!self.geocoder)
        
            self.geocoder = [[CLGeocoder alloc] init];
        

        NSString *hqAddress = [NSString stringWithFormat:@"%@", field.text];

        [self.geocoder geocodeAddressString:hqAddress completionHandler:^(NSArray *placemarks, NSError *error) 
            if ([placemarks count] > 0)
            
                CLPlacemark *placemark = [placemarks objectAtIndex:0];
                CLLocation *location = placemark.location;
                CLLocationCoordinate2D hqCoordinate = location.coordinate;

                NSLog (@"Your new HQ is at coordinates %f and %f", hqCoordinate.latitude, hqCoordinate.longitude);

                MKCoordinateRegion region;
                MKCoordinateSpan span;
                span.latitudeDelta = 0.01;
                span.longitudeDelta = 0.01;
                region.span = span;
                region.center = hqCoordinate;

                MKPointAnnotation *hqAnnotation = [[MKPointAnnotation alloc] init];
                [hqAnnotation setCoordinate:hqCoordinate];
                [hqAnnotation setTitle:@"HQ"];

                [[self mapView] addAnnotation:hqAnnotation];
                [self.mapView setRegion:region animated:TRUE];
                [self.mapView regionThatFits:region];

                //Save to NSUserDefaults
                NSUserDefaults *uDefaults = [NSUserDefaults standardUserDefaults];
                [uDefaults setDouble:hqCoordinate.latitude forKey:HQ_latitude];
                [uDefaults setDouble:hqCoordinate.longitude forKey:HQ_longitude];
                [uDefaults setBool:YES forKey:HQ_coordinates];
                [uDefaults synchronize];

            
        ];

    

    else
    
        //any actions for "Cancel"
    



//DEFINES WHAT SELECTING THE NEW PIN COLOR DOES
-(void)userDidSelectPinType:(AnnotationPinType)aPinType

    CustomAnnotation *selectedAnnotation = (CustomAnnotation *)[mapView.selectedAnnotations objectAtIndex:0];
    selectedAnnotation.pinType = aPinType;
    [mapView removeAnnotation:selectedAnnotation];
    [mapView addAnnotation:selectedAnnotation];
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];




@end

CustomAnnotation.m

#import "CustomAnnotation.h"
#import <CoreLocation/CoreLocation.h>

@implementation CustomAnnotation

@synthesize title, subtitle, coordinate;
@synthesize pinType;



-(id) initWithCoordinate:(CLLocationCoordinate2D)aCoordinate title:(NSString *)aTitle subtitle:(NSString *)aSubtitle



    if ((self = [super init]))
    
        self.title = aTitle;
        self.coordinate = aCoordinate;
        self.subtitle = aSubtitle;
    

    return self;



- (NSString *)annotationViewImageName

    switch (self.pinType)
    
        case 0:
            return @"Red_Pin.png";
            break;
        case 1:
            return @"Green_Pin.png";
            break;
        case 2:
            return @"Purple_Pin.png";
            break;
        default:
            break;
    


- (NSString *)title

    return title;


- (NSString *)subtitle

    return subtitle;


@end

PinSelectionViewController.m

#import "PinSelectionViewController.h"

@interface PinSelectionViewController ()

@end

@implementation PinSelectionViewController
@synthesize delegate;
@synthesize currentPinType;

- (id)initWithStyle:(UITableViewStyle)style

    self = [super initWithStyle:style];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];



- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


#pragma mark - Table view data source

- (void)tableView:(UITableView *) tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

    if(indexPath.row ==currentPinType)
        cell.accessoryType = UITableViewCellAccessoryCheckmark;



#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath


    [self.delegate userDidSelectPinType:indexPath.row];



@end

PinSelectionDelegateProtocol.h

#import <Foundation/Foundation.h>

typedef enum

    RED_PIN,
    GREEN_PIN,
    PURPLE_PIN
 AnnotationPinType;

@protocol PinSelectionDelegate <NSObject>

@required

-(void)userDidSelectPinType:(AnnotationPinType)aPinType;

@end

【问题讨论】:

【参考方案1】:

我看到的问题早在您的viewForAnnotation 方法中。您正确地重用了注释视图,但错误地假设重用的视图配置正确。当您检查视图是否为零时,您只需将全新的视图配置为具有与注释名称匹配的引脚颜色。您需要做的是检查它是否为 nil,如果是则创建一个新的并关闭 if。然后确保新的和重复使用的注释视图都按照您的需要设置了它们的引脚颜色、标题、附件视图等用于该注释

你也不能设置MKPinAnnotationView.image,它只会被覆盖。如果你真的想设置自定义图像,你必须使用常规的 MKAnnotationView。如果您可以使用标准的红色、绿色和蓝色引脚,只需将.pinColor 设置为您想要的任何值。

【讨论】:

感谢您的回复,您多次提供了很大的帮助。有没有更详细地介绍 mapkit 的书?我真的很想学习如何做到这一点,但这确实是一个挑战。谢谢! 我不知道任何 mapkit 书籍,但如果你打算推出一个应用程序,你必须注册开发程序,如果你是,你可以获得视频WWDC 解释了很多

以上是关于选择注释引脚时更改引脚颜色的主要内容,如果未能解决你的问题,请参考以下文章

多个注释数组,每个数组的引脚颜色不同?

iPhone:MKAnnotation Pin 颜色“选定状态”

Swift - 使用 UISwitch 更改引脚颜色

MapView 问题 - 地图重新加载时引脚更改颜色

MKMap 引脚颜色不显示

在 Swift 中的同一个 mapView 中分配多个注释 pinColors?