一、定位
1.1 定位概要
要实现地图、导航功能,往往需要先熟悉定位功能,在iOS中通过Core Location框架进行定位操作。Core Location自⾝可以单独使用,和地图开发框架MapKit完全是独立的,但是往往地图开发要配合定位框架使用。在Core Location 中主要包含了定位、地理编码(包括反编码)功能。
Core Location的主要功能:
1.获取经纬度
2.地理编码(根据给定的地名,获得具体的位置信息(如经纬度、地址的全称等))
3.反地理编码(根据给定的经纬度,获得具体的位置信息)
1.2 iOS 定位功能的实现
导入MapKit框架
#import <MapKit/MapKit.h>
签订MKMapViewDelegate协议 ,添加成员变量
@interface ViewController () <MKMapViewDelegate>
@property (nonatomic, strong) CLLocationManager* locationManager;
@end
设置地图的样式
MKMapTypeStandard = 0, 平面地图
MKMapTypeSatellite :卫星云图 (中图)
MKMapTypeHybrid :混合模式(普通地图覆盖于卫星云图之上 )
MKMapTypeSatelliteFlyover: 3D立体卫星 (iOS9.0)
MKMapTypeHybridFlyover: 3D立体混合 (iOS9.0)
self.mapView.mapType = MKMapTypeStandard;
是否显示用户位置
self.mapView.showsUserLocation = YES;
授权定位用户的位置,需要在info.plist文件中添加(以下二选一,两个都添加默认使用NSLocationWhenInUseUsageDescription):
- NSLocationWhenInUseUsageDescription 允许在前台使用时获取GPS的描述
- NSLocationAlwaysUsageDescription 允许永远可获取GPS的描述
if ([CLLocationManager instanceMethodForSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
}
定位的精确度
kCLLocationAccuracyBestForNavigation // 最适合导航
kCLLocationAccuracyBest; // 最好的
kCLLocationAccuracyNearestTenMeters; // 10m
kCLLocationAccuracyHundredMeters; // 100m
kCLLocationAccuracyKilometer; // 1000m
kCLLocationAccuracyThreeKilometers; // 3000m
// 精确度越高, 越耗电, 定位时间越长
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
每个多少米定位一次
_locationManager.distanceFilter = 10;
1.3 地理位置编码
地理编码(根据给定的地名,获得具体的位置信息(如经纬度、地址的全称等))
对应方法
- 地理编码方法-(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler
创建编码对象
@property (strong, nonatomic) CLGeocoder *geocoder;
创建一个block作为参数传递的方式
@property (strong, nonatomic) void(^geocodeComplatHandle)(NSString *name);
在手势方法里面调用[self geocoder:coordinate2D]
方法传递一个经纬度进去
- (void)geocoder:(CLLocationCoordinate2D)coordinate2D {
// 创建一个经纬度位置 CLLocation
CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate2D.latitude longitude:coordinate2D.longitude];
// 1、通过经纬度获取对应的地理位置,查询位置是一个异步操作
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placemark = [placemarks lastObject];
NSLog(@"%@ %@ %@",placemark.name, placemark.thoroughfare,placemark.subThoroughfare);
// 将地理位置名称显示在标注视图上
if (self.geocodeComplatHandle) {
self.geocodeComplatHandle(placemark.name,placemark.thoroughfare);
}
}];
}
1.4 地理位置反编码
对应方法
- 反地理编码方法-(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler
反地理编码(根据给定的经纬度,获得具体的位置信息)
- (IBAction)search:(id)sender {
[self.geocoder geocodeAddressString:self.searchText.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placemark = placemarks[0];
//创建并添加一个标注视图到mapView上
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = placemark.location.coordinate;
//将标注添加到地图上
[self.mapView addAnnotation:annotation];
}];
}
二、地图
2.1 地图(MapKit的基本概念)
在iOS6以后,苹果不再使用苹果地图,⽽是使用苹果⾃己的地图。我们使用Core Location来获取⽤户的位置信息,MapKit则是⽤来显⽰具体的信息。其核心是MKMapView类的使用,我们可以设置地图显示方式,控制地图,可以在地图上添加标注。
2.2 地图类型
- MKMapTypeStandard : 平面地图
- MKMapTypeSatellite :卫星云图 (中图)
- MKMapTypeHybrid :混合模式(普通地图覆盖于卫星云图之上 )
- MKMapTypeSatelliteFlyover: 3D立体卫星 (iOS9.0)
- MKMapTypeHybridFlyover: 3D立体混合 (iOS9.0)
MKMapViewDelegate协议方法
#pragma mark - <MKMapViewDelegate>
// 地图加载完成
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
NSLog(@"%s %f, %f",__func__, mapView.userLocation.coordinate.longitude, mapView.userLocation.coordinate.latitude);
}
// 用户位置更新后调用
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
//设置中心点
CLLocationCoordinate2D center = userLocation.location.coordinate;
// 设置跨度
MKCoordinateSpan span = {0.01,0.01};
// 设置地图显示的范围
[self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
NSLog(@"用户位置发生改变");
}
2.3 MKMapView添加标注视图
使用长按手势添加标注,创建一个长按手势,添加到mapView上面
UILongPressGestureRecognizer *longGest = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGestAction:)];
[self.mapView addGestureRecognizer:longGest];
手势方法实现
- (void)longGestAction:(UILongPressGestureRecognizer *)longGest {
// 获取触摸点所在地图上的CGPoint坐标
CGPoint point = [longGest locationInView:self.mapView];
// 将地图所在触摸点的坐标 CGPoint 转为对应的经纬度 CLLocationCoordinate2D
CLLocationCoordinate2D coordinate2D = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
if (longGest.state == UIGestureRecognizerStateBegan) {
// 创建并添加一个标注视图到mapView上
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.title = @"XXXX";
annotation.coordinate = coordinate2D;
annotation.subtitle = [NSString stringWithFormat:@"%f, %f",annotation.coordinate.latitude, annotation.coordinate.longitude];
[self setGeocodeComplatHandle:^(NSString *locationName1,NSString *locationName2) {
annotation.title = loationName1;
annotation.subtitle = locationName2;
}];
// 地理位置编码方法
[self geocoder:coordinate2D];
// 将标注添加到地图上
[self.mapView addAnnotation:annotation];
}
}
三、自定义标注视图
3.1 步骤:
1.⾃定义实现MKAnnotation的类并重新coordinate,title,subtitle属性。
2.实现MKMapViewDelegate的- mapView:viewForAnnotation: 方法。
自定义标注视图功能实现:
用户位置发生改变后调用
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
CLLocationCoordinate2D center = userLocation.location.coordinate;
MKCoordinateSpan span = {0.05,0.05};
[mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES];
}
添加了标注视图后调用
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views {
NSLog(@"添加了标注视图后调用");
}
添加标注视图时调用,这里可以自定义标注视图
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
NSLog(@"viewForAnnotation");
// 判断是否是用户当前的位置标注
if (![annotation isKindOfClass:[MKPointAnnotation class]]) {
return nil;
}
//设置重用标示符
static NSString *identifer = @"annotation";
//先从重用的队列中找
MKAnnotationView *annatationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifer];
大头针样式
// MKPinAnnotationView *annatationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifer];
是否显示辅助标注视图
annatationView.canShowCallout = YES;
设置大头针的颜色,前提是为MKPinAnnotationView类型
annatationView.pinTintColor = [UIColor orangeColor];
设置大头针出现的动画,前提是为MKPinAnnotationView类型
annatationView.animatesDrop = YES;
使用图片作为标注
annatationView.image = [UIImage imageNamed:@"icon"];
是否可以拖拽
annatationView.draggable = YES;
设置标注视图的偏移
annatationView.centerOffset = CGPointMake(0, -25);
设置辅助视图的偏移
annatationView.calloutOffset = CGPointMake(0, -10);
UIButton *leftView = [UIButton buttonWithType:UIButtonTypeCustom];
[leftView setImage:[UIImage imageNamed:@"头像"] forState:UIControlStateNormal];
leftView.tag = 100;
leftView.frame = CGRectMake(0, 0, 50, 50);
设置左边的辅助视图
annatationView.leftCalloutAccessoryView = leftView;
设置右边的辅助视图
annatationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
点击标注视图时调用
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
NSLog(@"didSelectAnnotationView");
}
点击左右辅助视图时调用
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
NSLog(@"%@",control);
}
地图开始加载时调用
- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView {
NSLog(@"地图开始加载时调用");
}
地图加载完成时调用
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
NSLog(@"地图加载完成时调用");
}
地图加载失败时调用
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error {
NSLog(@"地图加载失败时调用");
}
地图显示的范围将要发生改变时调用
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
NSLog(@"地图显示的范围将要发生改变时调用");
}
地图显示的范围改变后调用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(@"地图显示的范围改变后调用");
}
定位用户的位置失败
- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
NSLog(@"定位用户的位置失败");
}
标注视图拖拽后调用
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
fromOldState:(MKAnnotationViewDragState)oldState {
/** 拖拽的状态
MKAnnotationViewDragStateNone = 0, 没有拖拽
MKAnnotationViewDragStateStarting, 开始拖拽
MKAnnotationViewDragStateDragging, 正在拖拽
MKAnnotationViewDragStateCanceling, 取消拖拽
MKAnnotationViewDragStateEnding 结束拖拽
**/
NSLog(@"didChangeDragState");
}
来源:oschina
链接:https://my.oschina.net/u/2892206/blog/744068