(1)自定义大头针Annotation的样式,也就是定义view,主要的方法是如下,传递一个大头针annotation模型,然后返回一个MKAnnotationView,这个MKAnnotationView有一个image属性,设置这个属性,就能设置它的样式了。
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ }
关键提示,这个MKAnnotationView和tableViewCell类似,可以循环利用,先从mapView中取,取不到再创建。
主要代码:
#import "ViewController.h" #import <MapKit/MapKit.h> #import <CoreLocation/CoreLocation.h> #import "WPAnnotation.h" @interface ViewController ()<MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @property(nonatomic,strong) CLLocationManager *locMgr; @end @implementation ViewController -(CLLocationManager *)locMgr{ if (_locMgr==nil) { _locMgr=[[CLLocationManager alloc]init]; } return _locMgr; } - (void)viewDidLoad { [super viewDidLoad]; if ([[UIDevice currentDevice].systemVersion doubleValue]>=8.0) { [self.locMgr requestWhenInUseAuthorization]; } //设置代理 self.mapView.delegate=self; //添加两个大头针 WPAnnotation *anno0=[[WPAnnotation alloc]init]; anno0.coordinate=CLLocationCoordinate2DMake(40, 116); [email protected]"全聚德"; [email protected]"全北京最好的烤鸭店"; [email protected]"category_1"; [self.mapView addAnnotation:anno0]; WPAnnotation *anno1=[[WPAnnotation alloc]init]; anno1.coordinate=CLLocationCoordinate2DMake(39, 115); [email protected]"万达影院"; [email protected]"全中国最顶尖的观影圣地"; [email protected]"category_5"; [self.mapView addAnnotation:anno1]; } -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ static NSString *[email protected]"annoView"; MKAnnotationView *annoView=[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView==nil) { annoView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:ID]; //点击大头针出现信息(自定义view的大头针默认点击不弹出) annoView.canShowCallout=YES; } //再传递一次annotation模型(赋值) annoView.annotation=annotation; WPAnnotation *anno=annotation; annoView.image=[UIImage imageNamed:anno.icon]; return annoView; } @end
大头针模型,多了一个icon属性,因为我们要自定义大头针,所以需要图形属性:
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface WPAnnotation : NSObject<MKAnnotation> @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subtitle; //自定义大头针图片 @property(nonatomic,copy) NSString *icon; @end
(2)如果我们加入追踪用户现有位置时
//追踪用户位置 self.mapView.userTrackingMode=MKUserTrackingModeFollow;
发现会有如下报错:[MKUserLocation icon]: unrecognized selector sent to instance 0x7f89baecab50
主要原因是,追踪用户位置的MKUserLocation也是一个大头针(蓝色发光的那个圈圈),它也要经过viewForAnnotation这个代理方法返回自定义的大头针,但是它是没有icon属性的,所以报错。我们应该在viewForAnnotation中添加一个判断:
//如果是系统自带的大头针,则返回默认的,否则下面要设置icon时会报错,因为系统的大头针没有icon属性 if (![annotation isKindOfClass:[WPAnnotation class]]) return nil;
(3)还有一个MKPinAnnotationView是MKAnnotationView的子类,属性多2个,一个是设置颜色,就是可以设置大头针的颜色,还有一个是设置大头针从天而降。
- (void)viewDidLoad { [super viewDidLoad]; ...... [self.mapView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapMapView:)]]; } -(void)tapMapView:(UITapGestureRecognizer *)tap{ //获取点 CGPoint point=[tap locationInView:tap.view]; //点转坐标 CLLocationCoordinate2D coordi=[self.mapView convertPoint:point toCoordinateFromView:self.mapView]; WPAnnotation *anno=[[WPAnnotation alloc]init]; anno.coordinate=coordi; [email protected]"全聚德"; [email protected]"来一只鸭子,老板!"; [self.mapView addAnnotation:anno]; } -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ static NSString *[email protected]"map"; MKPinAnnotationView *annoView=(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView==nil) { annoView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:ID]; //设置描述信息能点击出现 annoView.canShowCallout=YES; //设置颜色 annoView.pinColor=MKPinAnnotationColorGreen; //设置第一次出现从天而降 annoView.animatesDrop=YES; } return annoView; }
(4)自定义一个MKAnnotationView,并利用代理方法,监听大头针的点击,点击后,再弹出一个“大头针”(只不过这个大头针是自定义MkAnnotationView的)。
我们一般返回一个大头针视图,用下面这个类似于tableViewCell的方法。
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ if ([annotation isKindOfClass:[WPDescriptionAnnotation class]]) { WPAnnotationView *annoView=[WPAnnotationView annotationWithMapView:mapView]; annoView.annotation=annotation; return annoView; }else if ([annotation isKindOfClass:[WPAnnotation class]]){ WPTuanGouAnnotationView *annoView=[WPTuanGouAnnotationView annotationWithMapView:mapView]; annoView.annotation=annotation; return annoView; } return nil; }
点击某一个大头针视图,也类似于点击tableView的某一行(这里有一些判断语句十分实用):
//点击大头针,弹出一个自定义的大头针充当描述信息 -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{ if (![view isKindOfClass:[WPTuanGouAnnotationView class]]) return; //删除所有再添加,保证只有1个,也防止重复 for (id annotation in mapView.annotations) { if ([annotation isKindOfClass:[WPDescriptionAnnotation class]]) { [mapView removeAnnotation:annotation]; } } WPAnnotation *anno=view.annotation; WPDescriptionAnnotation *descAnno=[[WPDescriptionAnnotation alloc]init]; descAnno.tuangou=anno.tuangou; [mapView addAnnotation:descAnno]; }
我们一般在项目中添加大头针,是有数据模型的。先把这个数据模型赋值给大头针,然后再添加。当然,大头针需要在自己的类中设置setTuangou也就是设置数据模型。
for (WPTuanGou *tuan in self.tuangous) { WPAnnotation *anno=[[WPAnnotation alloc]init]; anno.tuangou=tuan; [self.mapView addAnnotation:anno]; }
我们一般在项目中,都是把模型和大头针,当做参数在不同的对象之间传递。
(5)导航划线
#import "ViewController.h" #import <CoreLocation/CoreLocation.h> #import <MapKit/MapKit.h> #import "WPAnnotation.h" @interface ViewController ()<MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @property(nonatomic,strong) CLGeocoder *geocoder; @end @implementation ViewController -(CLGeocoder *)geocoder{ if (_geocoder==nil) { _geocoder=[[CLGeocoder alloc]init]; } return _geocoder; } - (void)viewDidLoad { [super viewDidLoad]; self.mapView.delegate=self; NSString *[email protected]"广州"; NSString *[email protected]"北京"; //这个方法只能生效1个,所以不能分开写 [self.geocoder geocodeAddressString:add1 completionHandler:^(NSArray *placemarks, NSError *error) { if (error) return; CLPlacemark *fromPm=[placemarks firstObject]; [self.geocoder geocodeAddressString:add2 completionHandler:^(NSArray *placemarks, NSError *error) { CLPlacemark *toPm=[placemarks firstObject]; [self addLineFrom:fromPm to:toPm]; }]; }]; } -(void)addLineFrom:(CLPlacemark *)fromPm to:(CLPlacemark *)toPm{ //添加2个大头针 WPAnnotation *anno0=[[WPAnnotation alloc]init]; anno0.coordinate=fromPm.location.coordinate; [self.mapView addAnnotation:anno0]; WPAnnotation *anno1=[[WPAnnotation alloc]init]; anno1.coordinate=toPm.location.coordinate; [self.mapView addAnnotation:anno1]; //设置方向请求 MKDirectionsRequest *request=[[MKDirectionsRequest alloc]init]; //设置起点终点 MKPlacemark *sourcePm=[[MKPlacemark alloc]initWithPlacemark:fromPm]; request.source=[[MKMapItem alloc]initWithPlacemark:sourcePm]; MKPlacemark *destiPm=[[MKPlacemark alloc]initWithPlacemark:toPm]; request.destination=[[MKMapItem alloc]initWithPlacemark:destiPm]; //定义方向对象 MKDirections *dirs=[[MKDirections alloc]initWithRequest:request]; //计算路线 [dirs calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { NSLog(@"总共有%lu条线路",(unsigned long)response.routes.count); for (MKRoute *route in response.routes) { [self.mapView addOverlay:route.polyline]; } }]; } //划线就是添加路径,就是添加遮盖 -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{ MKPolylineRenderer *renderer=[[MKPolylineRenderer alloc]initWithOverlay:overlay]; renderer.strokeColor=[UIColor redColor]; return renderer; } @end
还有一种方式创建导航,即利用MKMapItem:
MKMapItem *from=[[MKMapItem alloc]initWithPlacemark:[[MKPlacemark alloc] initWithPlacemark:fromPm]]; MKMapItem *to=[[MKMapItem alloc]initWithPlacemark:[[MKPlacemark alloc] initWithPlacemark:toPm]]; NSMutableDictionary *options=[NSMutableDictionary dictionary]; options[MKLaunchOptionsDirectionsModeKey]=MKLaunchOptionsDirectionsModeDriving; options[MKLaunchOptionsShowsTrafficKey][email protected]; [MKMapItem openMapsWithItems:@[from,to] launchOptions:options];