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.1viewDidLoad 中的加載
1 #import "ViewController.h" 2 #import "MapKit/MapKit.h" 3 #import "MyPointAnnotation.h" 4 #import "MyAnnotationView.h" 5 6 @interface ViewController (){ 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)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)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* _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 #import4 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 #import3 #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 )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