接第五步,当一个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:
点击大头针:
虽然丑了点,但意思到了。。。