[IOS地图开发系类]6、自定义地图标注MKAnnotationView

  接第五步,当一个MKAnnotationView被点击后,会触发地图MKMapViewDelegate的方法

didSelectAnnotationView,点击空白处或其他的MKAnnotationView时,会触发

didDeselectAnnotationView,

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view NS_AVAILABLE(NA, 4_0);
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view NS_AVAILABLE(NA, 4_0);

    我们可以利用这两个方法,在用户点击大头针时,弹出一个自定义的试图,对该地点进行标记说明,这个就是本次博文的内容了。

首先,修改下前面的CustomAnnotation这个类,添加一个type属性,用于标记类型,本次,我们用到了两种类别的Annotation,一个是用于展示大头针的,一个是展示大头针上弹出视图的:

//
//  CustomAnnotation.h
//  LBS_002_mapview
//
//  Created by liqun on 13-7-25.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

#define PIN_RED @"Red"
#define PIN_GREEN @"Green"
#define PIN_PURPLE @"Purple"
@interface CustomAnnotation : NSObject<MKAnnotation>

@property (nonatomic, assign, readonly)     CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, readonly)       NSString *title;
@property (nonatomic, copy, readonly)       NSString *subtitle;
@property (nonatomic, assign)int type;//0----pin  1---pop

@property (nonatomic, unsafe_unretained) MKPinAnnotationColor pinColor;
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
                     title:(NSString *)paramTitle
                  subTitle:(NSString *)paramSubTitle;

+ (NSString *) reusableIdentifierforPinColor :(MKPinAnnotationColor)paramColor;
@end
实现文件:

//
//  CustomAnnotation.m
//  LBS_002_mapview
//
//  Created by liqun on 13-7-25.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import "CustomAnnotation.h"

@implementation CustomAnnotation

- (void)dealloc
{
    
    [_subtitle  release];
    [_title  release];
    
    [super dealloc];
}
- (id) initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
                     title:(NSString *)paramTitle
                  subTitle:(NSString *)paramSubTitle
{

    if (self = [super init]) {
        _coordinate = paramCoordinates;
        _title = [paramTitle copy];
        _subtitle = [paramSubTitle copy];
    }

    return self;
}


+ (NSString *) reusableIdentifierforPinColor :(MKPinAnnotationColor)paramColor{ NSString *result = nil;
    switch (paramColor){
        case MKPinAnnotationColorRed:{
            result = PIN_RED;
            break;
        }
        case MKPinAnnotationColorGreen:{
            result = PIN_GREEN;
            break;
        }
        case MKPinAnnotationColorPurple:{
            result = PIN_PURPLE;
            break;
        }
    }
    return result;
}
@end
其次,我们需定义一个弹出视图,类似于UITableViewCell的布局试图,这里,我就定义一个左边用UIImageView和右边用UILable的组合视图:

头文件

//
//  CustomAnnotationCell.h
//  LBS_002_mapview
//
//  Created by liqun on 13-7-29.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface CustomAnnotationCell : UIView
@property (nonatomic,retain)NSString* imageUrl;
@property (nonatomic,copy)NSString* title;
-(CustomAnnotationCell*)initWithTitle:(NSString*)ptitle WithImage:(NSString*)purl WithFrame:(CGRect)prt;
@end
实现文件:

//
//  CustomAnnotationCell.m
//  LBS_002_mapview
//
//  Created by liqun on 13-7-29.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import "CustomAnnotationCell.h"

@implementation CustomAnnotationCell

-(CustomAnnotationCell*)initWithTitle:(NSString*)ptitle WithImage:(NSString*)purl WithFrame:(CGRect)prt
{
    if (self = [super initWithFrame:prt]) {
        self.title = ptitle;
        self.imageUrl = purl;
        UIImageView* imgeView = [[UIImageView alloc] initWithFrame:CGRectMake(5,5, self.frame.size.width * 0.3, self.frame.size.height - 10)];
        imgeView.image = [UIImage imageNamed:purl];
        [self addSubview:imgeView];
        [imgeView release];
        
        UILabel* titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width * 0.3 + 5, 5, self.frame.size.width - (self.frame.size.width * 0.3 + 5), self.frame.size.height - 10)];
        titleLabel.text = ptitle;
        titleLabel.numberOfLines = 2;
       [titleLabel sizeToFit];
        [self addSubview:titleLabel];
        [titleLabel release];
        
        
        
    }
    
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

@end
上面这个自定义的View,会被添加到我们自定义的

MKAnnotationView的子CustomMKAnnotationView上,前面说过,MKPinAnnotationView也是MKAnnotationView的子类,我们这次定义的这个CustomMKAnnotationView,和MKPinAnnotationView是一个级别的,可以作为

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation的返回视图,

头文件:

//
//  CustomMKAnnotationView.h
//  LBS_002_mapview
//
//  Created by liqun on 13-7-29.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import <MapKit/MapKit.h>

@interface CustomMKAnnotationView : MKAnnotationView
@property (nonatomic,retain)UIView *contentView;
- (id)initWithFrame:(CGRect)rct  Annotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
;
@end
实现文件,主要做背景绘制工作:

//
//  CustomMKAnnotationView.m
//  LBS_002_mapview
//
//  Created by liqun on 13-7-29.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import "CustomMKAnnotationView.h"
#import <QuartzCore/QuartzCore.h>

@interface CustomMKAnnotationView() {

}
-(void)drawBackground:(CGContextRef)context;
- (void)drawArrowBoundPath:(CGContextRef)context;
@end

@implementation CustomMKAnnotationView

@synthesize contentView;

- (void)dealloc
{
    self.contentView = nil;
    [super dealloc];
}

- (id)initWithFrame:(CGRect)rct  Annotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.canShowCallout = NO;
         self.frame = rct;
        self.centerOffset = CGPointMake(0, -(self.frame.size.height/2.0 + 25));
       
        
        UIView *_contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - 15)];
        _contentView.backgroundColor   = [UIColor clearColor];
        
        [self addSubview:_contentView];
        [_contentView release];
        self.contentView = _contentView;
        
    }
    return self;
}

-(void)drawBackground:(CGContextRef)context
{
    CGContextSetLineWidth(context, 2.0);
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    [self drawArrowBoundPath:context];
    CGContextFillPath(context);
    
}
- (void)drawArrowBoundPath:(CGContextRef)context
{
    CGRect rrect = self.bounds;
	CGFloat radius = 6.0;
    
	CGFloat minx = CGRectGetMinX(rrect),
    midx = CGRectGetMidX(rrect),
    maxx = CGRectGetMaxX(rrect);
	CGFloat miny = CGRectGetMinY(rrect),
    maxy = CGRectGetMaxY(rrect)-15;
    CGContextMoveToPoint(context, midx+15, maxy);
    CGContextAddLineToPoint(context,midx, maxy+15);
    CGContextAddLineToPoint(context,midx-15, maxy);
    
    CGContextAddArcToPoint(context, minx, maxy, minx, miny, radius);
    CGContextAddArcToPoint(context, minx, minx, maxx, miny, radius);
    CGContextAddArcToPoint(context, maxx, miny, maxx, maxx, radius);
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    CGContextClosePath(context);
}

- (void)drawRect:(CGRect)rect
{
	[self drawBackground:UIGraphicsGetCurrentContext()];
    
    self.layer.shadowColor = [[UIColor blackColor] CGColor];
    self.layer.shadowOpacity = 1.0;
    self.layer.shadowOffset = CGSizeMake(-0.5f, 0.5f);
}
@end
然后将上述视图加到map上,主要思路是:

先把把type=0的大头针CustomAnnotation加到地图上,地图代理

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation

返回要MKPinAnnotationView的视图,当用户选择这个MKPinAnnotationView时,我们再添加一个type=1的弹出视图CustomAnnotation,然后再在地图代理中返回我们自定义的CustomMKAnnotationView,再把那个包含有个UIImageView和Label的自定义视图加到这个CustomMKAnnotationView上,便能实现本次要达到的效果:

直接上主要实现逻辑的控制器ViewControlelr:

//
//  ViewController.m
//  LBS_002_mapview
//
//  Created by liqun on 13-7-25.
//  Copyright (c) 2013年 Block Cheng. All rights reserved.
//

#import "ViewController.h"
#import <MapKit/MapKit.h>
#import "CustomAnnotation.h"
#import "CustomMKAnnotationView.h"
#import "CustomAnnotationCell.h"

@interface ViewController ()<CLLocationManagerDelegate,MKMapViewDelegate>
@property (nonatomic,retain)MKMapView* mapView;
@property (nonatomic,retain)CLLocationManager* locationManager;
@property (nonatomic,retain)CLLocation* location;
@property (nonatomic, retain) CLGeocoder *myGeocoder;


@property (nonatomic,retain)CustomMKAnnotationView* popMKAnnotation;
@property (nonatomic,retain)CustomAnnotation* pinAnnotation;
@property (nonatomic,retain)CustomAnnotation* popAnnotation;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    MKMapView* map = [[MKMapView alloc] initWithFrame:self.view.frame];
    map.mapType = MKMapTypeStandard;
    map.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:map];
    [map release];
    self.mapView = map;
    self.mapView.delegate = self;
    
    UIButton *addBt = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    addBt.frame = CGRectMake(0, 00, 320, 50);
    [addBt setTitle:@"locationMe" forState:UIControlStateNormal];
   
    [ addBt addTarget:self action:@selector(handleLocationMe:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview: addBt];
    
    if ([CLLocationManager locationServicesEnabled]){
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        self.locationManager.purpose =
        @"To provide functionality based on user's current location.";
        [self.locationManager startUpdatingLocation];
    } else {
        NSLog(@"Location services are not enabled");
    }
    
    self.myGeocoder = [[CLGeocoder alloc] init];
    
}

#pragma mark --
#pragma mark --mapView delegate
- (void)mapView:(MKMapView *)pmapView didSelectAnnotationView:(MKAnnotationView *)view NS_AVAILABLE(NA, 4_0)
{
    NSLog(@"didSelectAnnotationView");
    if ([view isKindOfClass:[MKPinAnnotationView class]]) {
         NSLog(@"you have selected the pinView");
        CustomAnnotation* annotation = (CustomAnnotation*)(view.annotation);
        if (annotation.type == 0){
            if (self.popAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
                self.popAnnotation.coordinate.longitude == view.annotation.coordinate.longitude) {
                return;
            }
            if (self.popAnnotation) {
                [pmapView removeAnnotation:self.popAnnotation];
                self.popAnnotation = nil;
            }
           
            CustomAnnotation* popAn = [[CustomAnnotation alloc] initWithCoordinates:CLLocationCoordinate2DMake(view.annotation.coordinate.latitude,view.annotation.coordinate.longitude) title:@"" subTitle:@""];
            self.popAnnotation = popAn;
            [popAn release];
            self.popAnnotation.type = 1;
            [pmapView addAnnotation:self.popAnnotation];
            [pmapView setCenterCoordinate:self.popAnnotation.coordinate animated:YES];
        } 
       
	}else if ([view isKindOfClass:[CustomMKAnnotationView class]]){
        
     NSLog(@"you have selected the popView");
    }
    
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view NS_AVAILABLE(NA, 4_0)
{
       NSLog(@"didDeselectAnnotationView %@ ---%@",view,[view.annotation class]);
    if ([view isKindOfClass:[CustomMKAnnotationView class]]) {
        NSLog(@"Unselected the popView");
        if (self.popAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
            self.popAnnotation.coordinate.longitude == view.annotation.coordinate.longitude) {
            NSLog(@"remove the pop view");
            [mapView removeAnnotation:self.popAnnotation];
            self.popAnnotation = nil;
        }
    } else if ([view isKindOfClass:[MKPinAnnotationView class]]) {
        NSLog(@"Unselected the pinView");
        if (self.popAnnotation &&  self.popAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&&
            self.popAnnotation.coordinate.longitude == view.annotation.coordinate.longitude) {
            NSLog(@"remove the pop view");
            [mapView removeAnnotation:self.popAnnotation];
            self.popAnnotation = nil;
        }
        
    }
    

}


- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *result = nil;
    if ([annotation isKindOfClass:[CustomAnnotation class]] == NO){
        return result;
    }
    if ([mapView isEqual:self.mapView] == NO){
        /* We want to process this event only for the Map View
         that we have created previously */
        return result;
    }
    /* First, typecast the annotation for which the Map View has
     fired this delegate message */
    CustomAnnotation *senderAnnotation = (CustomAnnotation *)annotation;
    //pinView
    if (senderAnnotation.type == 0 ) {
        /* Using the class method we have defined in our custom
         annotation class, we will attempt to get a reusable
         identifier for the pin we are about
         to create */
        NSString *pinReusableIdentifier =
        [CustomAnnotation reusableIdentifierforPinColor:senderAnnotation.pinColor];
        /* Using the identifier we retrieved above, we will
         attempt to reuse a pin in the sender Map View */
        MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:pinReusableIdentifier];
        if (annotationView == nil){
            /* If we fail to reuse a pin, then we will create one */
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:senderAnnotation reuseIdentifier:pinReusableIdentifier];
            /* Make sure we can see the callouts on top of
             each pin in case we have assigned title and/or
             subtitle to each pin */
            [annotationView setCanShowCallout:NO];
            annotationView.draggable = YES;
            annotationView.enabled = YES;
            
        }
        /* Now make sure, whether we have reused a pin or created a new one,
         
         that the color of the pin matches the color of the annotation */
        annotationView.pinColor = senderAnnotation.pinColor;
        //自定义图片时,不能用drop
        annotationView.animatesDrop = YES;
//        annotationView.image = [UIImage imageNamed:@"pin"];
        result = annotationView;
    } else {//popView
    
        NSString *popReusableIdentifier =@"popMKAnnotation";
        /* Using the identifier we retrieved above, we will
         attempt to reuse a pin in the sender Map View */
        CustomMKAnnotationView *annotationView = (CustomMKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:popReusableIdentifier];
        if (annotationView == nil){
            /* If we fail to reuse a pin, then we will create one */
            annotationView = [[CustomMKAnnotationView alloc] initWithFrame:CGRectMake(0, 0, 240, 80) Annotation:annotation reuseIdentifier:popReusableIdentifier];
            
            
        }
        CustomAnnotationCell  *cell = [[CustomAnnotationCell alloc] initWithTitle:@"This is a test mapPopView,Whick is like a UITableViewCell" WithImage:@"color_3" WithFrame:CGRectMake(0, 0, annotationView.frame.size.width, annotationView.frame.size.height - 15)];
        [annotationView.contentView addSubview:cell];
        cell.userInteractionEnabled = YES;
        [cell release];
        result = annotationView;
    }
    return result;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(IBAction)handleLocationMe:(id)sender
{
    [self.myGeocoder
     reverseGeocodeLocation:self.location completionHandler:^(NSArray *placemarks, NSError *error) {
         if (error == nil &&[placemarks count] > 0){
        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        /* We received the results */
        NSLog(@"Country = %@", placemark.country);
        NSLog(@"Postal Code = %@", placemark.postalCode);
        NSLog(@"Locality = %@", placemark.locality);
             NSLog(@"dic = %@", placemark.addressDictionary );
        NSLog(@"dic FormattedAddressLines= %@", [placemark.addressDictionary objectForKey:@"FormattedAddressLines"]);
             NSLog(@"dic Name = %@", [placemark.addressDictionary objectForKey:@"Name"]);
             NSLog(@"dic State = %@", [placemark.addressDictionary objectForKey:@"State"]);
             NSLog(@"dic Street = %@", [placemark.addressDictionary objectForKey:@"Street"]);
             NSLog(@"dic SubLocality= %@", [placemark.addressDictionary objectForKey:@"SubLocality"]);
             NSLog(@"dic SubThoroughfare= %@", [placemark.addressDictionary objectForKey:@"SubThoroughfare"]);
             NSLog(@"dic Thoroughfare = %@", [placemark.addressDictionary objectForKey:@"Thoroughfare"]);
        CLLocationCoordinate2D location =
        CLLocationCoordinate2DMake(self.location.coordinate.latitude, self.location.coordinate.longitude);
        /* Create the annotation using the location */
        CustomAnnotation *annotation =[[CustomAnnotation alloc] initWithCoordinates:location title:placemark.name subTitle:placemark.thoroughfare];
        /* And eventually add it to the map */
        annotation.pinColor = MKPinAnnotationColorPurple;
        annotation.type = 0;
        [self.mapView addAnnotation:annotation];
        [annotation release];
        self.pinAnnotation = annotation;
    }else if (error == nil &&
              [placemarks count] == 0){
         NSLog(@"No results were returned.");
     }else if (error != nil){
         NSLog(@"An error occurred = %@", error);
     }
     }];
}
#pragma mark --
#pragma mark --CCLocationManager delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
    /* We received the new location */
    NSLog(@"Latitude = %f", newLocation.coordinate.latitude);
    NSLog(@"Longitude = %f", newLocation.coordinate.longitude);
    self.location = newLocation;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    /* Failed to receive user's location */
}


- (void)dealloc
{
    self.mapView = nil;
    self.location = nil;
    self.locationManager = nil;
    
    self.myGeocoder = nil;
    self.popMKAnnotation = nil;
    self.pinAnnotation = nil;
    
    self.popAnnotation = nil;
    
    [super dealloc];
}

@end



运行效果图1:

[IOS地图开发系类]6、自定义地图标注MKAnnotationView

点击大头针:

[IOS地图开发系类]6、自定义地图标注MKAnnotationView

虽然丑了点,但意思到了。。。

你可能感兴趣的:(MkMapView,CLGeocoder)