1. 创建之前的准备工作
1.1 在Info.plist文件中添加下面两句话
NSLocationAlwaysUsageDescription —> 确定定位吗?亲
//请求的授权,除了可以在APP打开时允许定位服务,也可以在APP进入后台仍然可以使用定位服务(永久) --> 与上边一个可以二选一
[_locationManager requestAlwaysAuthorization];
NSLocationWhenInUseUsageDescripyion —>需要定位吗?
//此方法请求的授权,仅限于用户在打开使用APP时允许使用系统的定位服务(在应用使用期间)
[_locationManager requestWhenInUseAuthorization];
1.2 导入库文件 MapKit.framework 和 CoreLocation.framework
2. 工程创建说明 ---> 使用系统自带的MKPointAnnotation、MKPinAnnotationView 及自定义 MKPointAnnotation、MKPinAnnotationView
以下是ViewController.m 文件
2.1 viewDidLoad 中的加载
1 #import "ViewController.h" 2 #import "MapKit/MapKit.h" 3 #import "MyPointAnnotation.h" 4 #import "MyAnnotationView.h" 5 6 @interface ViewController ()<MKMapViewDelegate> { 7 8 MKMapView *_mapView; //地图对象 9 UILabel *_userLocationLable; //查看用户坐标 10 } 11 12 @end 13 14 @implementation ViewController 15 16 - (void)viewDidLoad { 17 [super viewDidLoad]; 18 19 //调用创建地图视图的方法 20 [self createMapView]; 21 //调用创建大头针的方法 22 [self createAnnotations]; 23 //调用这个方法调用所有的覆盖层的方法 24 [self overLay]; 25 //调用创建UI的方法 26 [self createUI]; 27 } 28 29 @end
2.2 创建地图视图的方法
1 //创建地图视图的方法 2 - (void)createMapView { 3 //创建地图对象 4 _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds]; 5 //设置map的类型 或地图模式 6 _mapView.mapType = MKMapTypeStandard; 7 /* 8 MKMapTypeStandard = 0, 纸张地图 标准地图 9 MKMapTypeSatellite, 纯卫星地图 10 MKMapTypeHybrid, 混合式地图 描述的卫星图 11 */ 12 //设置map的初始位置 13 //创建地理坐标2D 需要经度和纬度 如:经度:120.366486 纬度:36.083743 14 CLLocationCoordinate2D location = CLLocationCoordinate2DMake(36.083743, 120.366486); 15 //起始时 锁定一个矩形为1000 X 1000米的方位 ,坐标点location 16 _mapView.region = MKCoordinateRegionMakeWithDistance(location, 1000, 1000); 17 //设置地图能否放大缩小 18 _mapView.zoomEnabled = YES; 19 //设置地图能否滚动 20 _mapView.scrollEnabled = YES; 21 //设置显示用户的位置 先判断是否开始了定位服务 22 if ([CLLocationManager locationServicesEnabled] == YES) { 23 //显示用户的位置 24 _mapView.showsUserLocation = YES; 25 //设置用户的基本跟踪状态 26 [_mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:YES]; 27 28 /* 29 MKUserTrackingModeNone = 0, 不尾随 一般不设 30 MKUserTrackingModeFollow, 尾随用户位置,地图保存正向(北方向) 31 MKUserTrackingModeFollowWithHeading 随着地图旋转而尾随(地图方向和设备方向同步) 32 */ 33 } 34 //设置代理 需遵守MKMapViewDelegate代理协议 35 _mapView.delegate = self; 36 //将地图加入到self.view上 37 [self.view addSubview:_mapView]; 38 } 39 40 #pragma mark - 地图协议中的方法 - 41 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { 42 43 //这里判断必须要加,这个方法在刷新时会将用户的位置也会传到这个方法里,所以需要判断,如果不是大头针就是用户坐标点(蓝点),如果是蓝点(用户坐标点) 直接返回nil 44 if ([annotation isKindOfClass:[MKPointAnnotation class]] == NO) { 45 return nil; 46 } 47 48 //调用系统的方法 49 // MKPinAnnotationView *annotationView = [self systemMethodWithMapView:mapView andAnnotation:annotation]; 50 51 //调用自定义的方法 52 MKPinAnnotationView *annotationView = [self customMethodWithMapView:mapView andAnnotation:annotation]; 53 54 return annotationView; 55 } 56 57 //自定义的方法 58 - (MKPinAnnotationView *)customMethodWithMapView:(MKMapView *)mapView andAnnotation:(MKPointAnnotation *)annotation { 59 MyAnnotationView *annotationView = (MyAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomAnnotationView"]; 60 61 if (annotationView == nil) { 62 63 64 annotationView = [[MyAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomAnnotationView"]; 65 66 }else { 67 68 annotationView.annotation = annotation; 69 } 70 71 72 73 return annotationView; 74 } 75 76 77 //系统方法 78 - (MKPinAnnotationView *)systemMethodWithMapView:(MKMapView *)mapView andAnnotation:(MKPointAnnotation *)annotation { 79 80 // 类似于tableview的复用机制那个方法 81 MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"AnnotationView"]; 82 if (annotationView == nil) { 83 //如果从队列取 没有的话,需要创建新的大头针视图 84 annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"AnnotationView"]; 85 //设置大头针的色彩,默认是红色,还有绿色和紫色(了解) 86 annotationView.pinColor = MKPinAnnotationColorPurple; 87 //设置允许显示气泡(重要) 88 annotationView.canShowCallout = YES; 89 //设置下坠动画 (从上往下掉下来) 默认为NO 90 annotationView.animatesDrop = YES; 91 //设置是佛可以拖拽 92 annotationView.draggable = YES; 93 94 }else { 95 96 //如果有空闲,拿队列里空闲的view 然后显示大头针 97 annotationView.annotation = annotation; 98 99 } 100 return annotationView; 101 }
2.3 创建大头针的方法
1 //创建大头针的方法 2 - (void)createAnnotations { 3 //创建大头针1 4 MKPointAnnotation *annotation1 = [[MKPointAnnotation alloc] init]; 5 //设置title 6 annotation1.title = @"不知道是哪"; 7 //设置子title 8 annotation1.subtitle = @"真不知道是哪儿"; 9 //设置大头针的经纬度坐标 10 annotation1.coordinate = CLLocationCoordinate2DMake(-39.89, -79.88); 11 //把大头针1加入到地图上 12 [_mapView addAnnotation:annotation1]; 13 //创建大头针2 14 MKPointAnnotation *annotation2 = [[MKPointAnnotation alloc] init]; 15 annotation2.title = @"南半球"; 16 annotation2.subtitle = @"真是南半球"; 17 annotation2.coordinate = CLLocationCoordinate2DMake(-80.89, 156.456); 18 [_mapView addAnnotation:annotation2]; 19 //自定义方式创建大头针3 20 MyPointAnnotation *annotation3 = [[MyPointAnnotation alloc] initWithCoorDinate:CLLocationCoordinate2DMake(40.5, -88.7) title:@"第一个位置" subTitle:@"这里风景优美" information:@"这里是国家级旅游景点"]; 21 //自定义方式创建大头针4 22 MyPointAnnotation *annotation4 = [[MyPointAnnotation alloc] initWithCoorDinate:CLLocationCoordinate2DMake(37.68, -96.54) title:@"第二个位置" subTitle:@"这里有点冷" information:@"世界冰展所在地"]; 23 //将大头针3和4一块加入到地图上 用addAnnotations 24 [_mapView addAnnotations:@[annotation3,annotation4]]; 25 26 //将地图滚动到大头针3的位置 27 _mapView.centerCoordinate = annotation1.coordinate; 28 29 }
2.4 这个方法调用所有的覆盖层的方法
1 //这个方法调用所有的覆盖层的方法 2 - (void)overLay { 3 4 //调用绘制线的方法 5 [self pathOverLay]; 6 7 //调用多边形图层的方法 8 [self polyOverlay]; 9 10 //调用绘制圆的图层的方法 11 [self circleOverlay]; 12 13 } 14 15 //绘制圆的图层的方法 16 - (void)circleOverlay { 17 //圆图层和annotation一样需要添加到地图上,每个图层绘制都需要实现管理图层方法 18 CLLocationCoordinate2D centerLocation = CLLocationCoordinate2DMake(37.68, -96.54); 19 //绘制圆 20 MKCircle *circleOverlay = [MKCircle circleWithCenterCoordinate:centerLocation radius:100000]; 21 //添加到地图上 22 [_mapView addOverlay:circleOverlay]; 23 24 } 25 26 //多边形图层的方法 27 - (void)polyOverlay { 28 //设置多边形的角的坐标,记住一定要首尾相连 29 30 CLLocationCoordinate2D ploycoords[5] = { 31 CLLocationCoordinate2DMake(35.443, -77.876), 32 CLLocationCoordinate2DMake(36.553, -77.976), 33 CLLocationCoordinate2DMake(35.553, -79.567), 34 CLLocationCoordinate2DMake(34.443, -79.567), 35 CLLocationCoordinate2DMake(35.443, -77.876) 36 37 38 }; 39 40 MKPolygon *polygonOverlay = [MKPolygon polygonWithCoordinates:ploycoords count:5]; 41 //添加到地图上 42 [_mapView addOverlay:polygonOverlay]; 43 } 44 45 //绘制线的方法 46 - (void)pathOverLay { 47 CLLocationCoordinate2D pathCoords[6] = { 48 49 CLLocationCoordinate2DMake(33.123, -77.456), 50 CLLocationCoordinate2DMake(34.123, -78.456), 51 CLLocationCoordinate2DMake(32.123, -79.456), 52 CLLocationCoordinate2DMake(36.123, -71.456), 53 CLLocationCoordinate2DMake(35.123, -70.456), 54 CLLocationCoordinate2DMake(36.123, 73.456) 55 56 }; 57 58 //创建图层 59 MKPolyline *pathOverlay = [MKPolyline polylineWithCoordinates:pathCoords count:6]; 60 //添加到地图上 61 [_mapView addOverlay:pathOverlay]; 62 63 64 } 65 66 //管理图层视图 67 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { 68 69 if ([overlay isKindOfClass:[MKPolyline class]] == YES) { 70 MKPolylineRenderer *line = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; 71 //线的宽度 72 line.lineWidth = 2; 73 //设置线的颜色 74 line.strokeColor = [UIColor blueColor]; 75 76 return line; 77 78 }else if ([overlay isKindOfClass:[MKPolygon class]] == YES) { 79 80 MKPolygonRenderer *poly = [[MKPolygonRenderer alloc] initWithOverlay:overlay]; 81 //设置线宽 82 poly.lineWidth = 1; 83 //设置边缘颜色 84 poly.strokeColor = [UIColor greenColor]; 85 //设置填充颜色 86 poly.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.5]; 87 88 return poly; 89 90 }else if ([overlay isKindOfClass:[MKCircle class]] == YES) { 91 92 //创建圆视图 所有的视图都是overlay添加到构造方法参数 93 MKCircleRenderer *circle = [[MKCircleRenderer alloc] initWithOverlay:overlay]; 94 //设置边缘宽度 95 circle.lineWidth = 1; 96 //设置边缘颜色 97 circle.strokeColor = [UIColor redColor]; 98 //设置填充颜色 透明度0.4 99 circle.fillColor = [[UIColor greenColor] colorWithAlphaComponent:0.4]; 100 101 return circle; 102 } 103 104 return nil; 105 }
2.5 创建UI的方法 在创建该方法之前需要在AppDelegate.m 文件中将ViewController包装成导航控制器
1 //创建UI的方法 2 - (void)createUI { 3 4 _userLocationLable = [[UILabel alloc] initWithFrame:CGRectMake(0, 64, 320, 80)]; 5 [self.view addSubview:_userLocationLable]; 6 //创建BarButtonItem 这个是用户定位(跟随),参数放入一个MapView类型的地图对象 7 MKUserTrackingBarButtonItem *item = [[MKUserTrackingBarButtonItem alloc] initWithMapView:_mapView]; 8 //设置导航左边的BarButtonItem 9 self.navigationItem.leftBarButtonItem = item; 10 11 UIButton *hotSearchButton = [UIButton buttonWithType:UIButtonTypeCustom]; 12 hotSearchButton.frame = CGRectMake(0, 64, 100, 40); 13 [hotSearchButton setTitle:@"热点搜索" forState:UIControlStateNormal]; 14 15 [hotSearchButton addTarget:self action:@selector(hotSeatch) forControlEvents:UIControlEventTouchUpInside]; 16 17 18 [hotSearchButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 19 20 [self.view addSubview:hotSearchButton]; 21 22 23 UIButton *keywordSearchButton = [UIButton buttonWithType:UIButtonTypeCustom]; 24 25 keywordSearchButton.frame = CGRectMake(100, 64, 100, 40); 26 27 [keywordSearchButton setTitle:@"关键字搜索" forState:UIControlStateNormal]; 28 29 [keywordSearchButton addTarget:self action:@selector(keywordSearch) forControlEvents:UIControlEventTouchUpInside]; 30 [keywordSearchButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 31 32 [self.view addSubview:keywordSearchButton]; 33 34 //添加一个长按的手势 用长按的手势添加大头针 35 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; 36 longPress.minimumPressDuration = 1; 37 //长按手势加入到地图 38 [_mapView addGestureRecognizer:longPress]; 39 } 40 41 //长按手势执行的方法 42 - (void)longPress:(UILongPressGestureRecognizer *)longPress { 43 //注:一定别忘了判断 44 //判断长按手势状态 如果是开始的状态,就执行判断题 45 if (longPress.state == UIGestureRecognizerStateBegan) { 46 //在地图上找到CGPoint坐标(屏幕坐标) 47 CGPoint point = [longPress locationInView:_mapView]; 48 //屏幕坐标转成经纬度坐标 49 CLLocationCoordinate2D coordinate = [_mapView convertPoint:point toCoordinateFromView:_mapView]; 50 //创建大头针 51 52 MyPointAnnotation *annotation = [[MyPointAnnotation alloc] initWithCoorDinate:coordinate title:@"手势加入" subTitle:@"长按手势" information:@"长按手势信息"]; 53 54 55 //加入到地图上 56 [_mapView addAnnotation:annotation]; 57 58 } 59 60 61 } 62 63 64 - (void)hotSeatch { 65 //创建本地搜索请求 66 MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init]; 67 //设置搜索热点词(自然语言) 68 request.naturalLanguageQuery = @"学校"; 69 //设置搜索范围,以某个原点为中心,向外扩展一段经纬度距离范围 70 CLLocationCoordinate2D origionpoint = CLLocationCoordinate2DMake(36.08397, 120.37126); 71 //设置经纬度跨越范围 72 MKCoordinateSpan span = MKCoordinateSpanMake(0.3, 0.3); 73 //设置经纬度搜索区域 74 MKCoordinateRegion region = MKCoordinateRegionMake(origionpoint, span); 75 //将区域赋值给搜索请求对象中的region属性中 76 request.region = region; 77 //将地图移动到该区域 78 [_mapView setRegion:region]; 79 80 //创建本地搜索对象 81 MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request]; 82 //开启搜索 83 [search startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) { 84 85 if (error == nil) { 86 87 //搜索成功 88 //获取搜索结果 89 NSArray *arrResult = response.mapItems; 90 91 for (MKMapItem *item in arrResult) { 92 93 //先取出地图目的坐标对象(标记) 94 MKPlacemark *placeMark = item.placemark; 95 /* 96 地标里存放的经纬度,以及位置的地理信息说明,如名字、街道等等 97 */ 98 //创建大头针 99 MyPointAnnotation *annotation = [[MyPointAnnotation alloc] initWithCoorDinate:placeMark.location.coordinate title:placeMark.name subTitle:placeMark.locality information:placeMark.locality]; 100 101 //加入到地图中 102 [_mapView addAnnotation:annotation]; 103 } 104 105 106 }else { 107 NSLog(@"搜索失败"); 108 109 } 110 111 }]; 112 113 } 114 115 //关键字搜索 116 - (void)keywordSearch { 117 //创建地理编码 118 CLGeocoder *geocoder = [[CLGeocoder alloc] init]; 119 //正向地理编码 120 [geocoder geocodeAddressString:@"青岛科技大学" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) { 121 122 if (error == nil) { 123 //解析地理位置成功 124 //成功后遍历数组 125 for (CLPlacemark *place in placemarks) { 126 127 //创建大头针 128 129 MyPointAnnotation *annotation = [[MyPointAnnotation alloc] initWithCoorDinate:place.location.coordinate title:place.name subTitle:place.locality information:place.locality]; 130 //将大头针加入到地图 131 [_mapView addAnnotation:annotation]; 132 133 } 134 135 }else { 136 137 NSLog(@"正向地理编码解析失败"); 138 } 139 140 141 }]; 142 143 } 144 145 146 //完成更新用户定位 147 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { 148 149 150 _userLocationLable.text = [NSString stringWithFormat:@"用户位置: %.5f, %.5f",userLocation.coordinate.latitude, userLocation.coordinate.longitude]; 151 NSLog(@"%@",_userLocationLable.text); 152 153 }
3. 自定义 MyPointAnnotation 工程如下:
1 MyPointAnnotation.h文件 2 3 #import <MapKit/MapKit.h> 4 5 @interface MyPointAnnotation : MKPointAnnotation 6 7 /** 大头针信息 */ 8 @property(nonatomic, copy) NSString *information; 9 10 //构造方法 11 - (id)initWithCoorDinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title subTitle:(NSString *)subTitle information:(NSString *)information; 12 13 @end 14 15 MyPointAnnotation.m文件 16 17 #import "MyPointAnnotation.h" 18 19 @implementation MyPointAnnotation 20 21 - (id)initWithCoorDinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title subTitle:(NSString *)subTitle information:(NSString *)information { 22 23 if (self = [super init]) { 24 //标题 25 self.title = title; 26 //子标题 27 self.subtitle = subTitle; 28 //坐标 29 self.coordinate = coordinate; 30 //信息 31 self.information = information; 32 } 33 return self; 34 } 35 36 @end
4. 自定义 MyAnnotationView工程如下:
1 MyAnnotationView.h文件 2 #import <MapKit/MapKit.h> 3 #import "MyPointAnnotation.h" //导入自定义的大头针 4 @interface MyAnnotationView : MKPinAnnotationView { 5 6 MyPointAnnotation *myPointAnnotation; 7 8 } 9 10 //静态图片需要继承这个 11 //@interface MyAnnotationView : MKAnnotationView { 12 // MyPointAnnotation *myPointAnnotation; 13 //} 14 15 @end 16 17 18 MyAnnotationView.m文件 19 #import "MyAnnotationView.h" 20 21 @implementation MyAnnotationView 22 23 - (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier { 24 if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) { 25 //保存参数-传过来的大头针 26 myPointAnnotation = annotation; 27 28 //创建图片 29 UIImage *image = [UIImage imageNamed:@"pink"]; 30 31 //这种方式只适合静态图片 ,不适合动态和拖拽动态功能,它们有冲突 需要更改一下.h文件中的继承 32 //这种方式继承MKAnnotationView 否则没有效果 33 // NSData *imageData = UIImagePNGRepresentation(image); 34 // //处理imageData 比例5 35 // image = [UIImage imageWithData:imageData scale:5]; 36 // //修改当前视图的大小 37 // self.frame = CGRectMake(0, 0, 40, 40); 38 // //设置图片 39 // self.image = image; 40 // //设置填充模式 按比例填满 41 // self.contentMode = UIViewContentModeScaleToFill; 42 43 44 UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(-15, -5, 45, 45)]; 45 imageView.image = image; 46 [self addSubview:imageView]; 47 48 //允许气泡弹出 49 self.canShowCallout = YES; 50 //拖拽 51 self.draggable = YES; 52 //下坠动画 53 self.animatesDrop = YES; 54 55 56 UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeInfoDark]; 57 [leftButton addTarget:self action:@selector(leftButton) forControlEvents:UIControlEventTouchUpInside]; 58 //设置左边访问view 59 self.leftCalloutAccessoryView = leftButton; 60 61 UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; 62 [rightButton addTarget:self action:@selector(rightButton) forControlEvents:UIControlEventTouchUpInside]; 63 //设置右边访问view 64 self.rightCalloutAccessoryView = rightButton; 65 66 } 67 return self; 68 } 69 70 71 - (void)leftButton { 72 NSLog(@"leftButton:%@",myPointAnnotation.title); 73 } 74 75 - (void)rightButton { 76 NSLog(@"rightButton:%@",myPointAnnotation.information); 77 } 78 79 @end