[IOS地图开发系类]6、自定义地图标注MKAnnotationView
发布日期:2021-09-11 14:30:25 浏览次数:49 分类:技术文章

本文共 18397 字,大约阅读时间需要 61 分钟。

hot3.png

  接第五步,当一个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 
#import
#define PIN_RED @"Red"#define PIN_GREEN @"Green"#define PIN_PURPLE @"Purple"@interface CustomAnnotation : NSObject
@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 
@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 
@interface CustomMKAnnotationView : MKAnnotationView@property (nonatomic,retain)UIView *contentView;- (id)initWithFrame:(CGRect)rct Annotation:(id
)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 
@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
)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 
#import "CustomAnnotation.h"#import "CustomMKAnnotationView.h"#import "CustomAnnotationCell.h"@interface ViewController ()
@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
)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:

点击大头针:

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

转载于:https://my.oschina.net/chengliqun/blog/148318

转载地址:https://blog.csdn.net/weixin_34413802/article/details/92443943 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:net中webservice异步调用
下一篇:会员信息录入时,性别项应该怎么填写最合理呢?

发表评论

最新留言

不错!
[***.144.177.141]2024年03月22日 21时57分59秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

【大话Mysql面试】-Mysql常见面试题目 2019-04-26
08 【多线程高并发】Java线程间通信的方式 2019-04-26
【数据结构与算法】什么是跳表?通俗易懂来理解跳表 2019-04-26
【数据结构与算法】什么是图?图是什么?快速带你回顾图有关的知识点 2019-04-26
【数据结构与算法】什么是串?什么是KMP算法?字符串匹配是什么? 2019-04-26
【数据结构与算法】什么是布隆过滤器?如何防止缓存穿透的问题? 2019-04-26
【Java锁体系】CopyOnWriteArrayList是什么?线程安全的arraylist是哪个? 2019-04-26
【面试题目】Java设计模式你有哪些了解?说几个常用的。 2019-04-26
【计算机操作系统】常说的死锁是什么?死锁产生的必要条件是什么?死锁的解决策略是什么? 2019-04-26
【计算机操作系统】进程管理详解?进程与线程区别是什么?进程调度的算法有哪些?进程通信有哪些? 2019-04-26
【计算机操作系统】虚拟内存是什么?分页系统地址映射?页面置换算法有哪些?分段地址映射又是什么? 2019-04-26
【计算机操作系统】设备管理?磁盘结构是怎么样的?磁盘调度算法有哪些? 2019-04-26
【多线程高并发】为什么要使用多线程?创建多少个线程合适呢? 2019-04-26
【多线程与高并发】 Java两个线程轮流打印1-100两个数?多线程轮流打印数字? 2019-04-26
【多线程与高并发】 Java两个线程轮流打印字符串? 2019-04-26
【Linux命令篇】Linux命令实践 2019-04-26
【Leetcode单调队列】Leetcode239 滑动窗口最大值 2019-04-26
【Leetcode-单调栈】单调栈相关的题目-下一个更大的元素I 每日温度 2019-04-26
【Leetcode单调队列】- 洛谷P1714切蛋糕 2019-04-26
【Leetcode优先级队列】- 数据流的中位数 2019-04-26