专业术语 1. LBS :Location Based Service
2. SoLoMo :Social Local Mobile(索罗门)
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;经纬度
@property(readonly, nonatomic) CLLocationDistance altitude;海拔
@property(readonly, nonatomic) CLLocationDirection course;路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)
@property(readonly, nonatomic) CLLocationSpeed speed;行走速度(单位是m/s)
@property(assign, nonatomic) CLLocationDistance distanceFilter;每隔多少米定位一次
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;定位精确度(越精确就越耗电)
CLLocationCoordinate2D是一个用来表示经纬度的结构体,一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D
typedef struct {
CLLocationDegrees latitude; // 纬度
CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;
中国的经纬度范围
纬度范围:N 3°51′ ~ N 53°33′
经度范围:E 73°33′ ~ E 135°05′
中国部分城市的经纬度
用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法可以计算2个位置之间的距离
一、获取用户的位置
1、在应⽤中使用CoreLocation,需要将框架 CoreLocation 加入项⺫标,并且根据需要导入Core Location 头文件
#import<CoreLocation/CoreLocation.h> //用于地理定位
2、要在应用中使用MapKit,需要将框架MapKit加入项目标,并在所用它的类中导入MapKit头文件
#import<MapKit/MapKit.h> //用于地图展示
3、Core Location 尊重用户隐私,仅在用户许可时获取设备的当前位置。在应用“设置”的“隐私”部 分,可以关闭或开启定位服务,还可以禁止或允许特定应用获取位置信息, 要请求用户允许使⽤定位服务,应用需要让CLLocationManager实例开始更新当前位置或将 MKMapView实例的属性 ShowsUserLocation设置为YES。如果设备关闭了定位服务,Core Location将提醒用户在应用“设置”中开启定位服务;如果Core Location以前未请求⽤户允许获取 设备的位置,它将显示一个提示框,请求⽤户许可。
//CoreLocation中使用CLLocationManager对象来做用户定位
self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; [self.locationManager startUpdatingLocation];
//授权状态 if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { //申请授权 [self.locationManager requestWhenInUseAuthorization]; }
// kCLAuthorizationStatusNotDetermined = 0//用户尚未做出决定是否启用定位服务
// kCLAuthorizationStatusRestricted//没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
// kCLAuthorizationStatusDenied//用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
// kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(NA, 8_0)//应用获得授权可以一直使用定位服务,即使应用不在使用状态
// kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0)//使用此应用过程中允许访问定位服务
// kCLAuthorizationStatusAuthorized NS_ENUM_DEPRECATED(10_6, NA, 2_0, 8_0, "Use kCLAuthorizationStatusAuthorizedAlways") = kCLAuthorizationStatusAuthorizedAlways//已经废弃
4、检查定位服务是否开启
//GPS硬件打开 if (![CLLocationManager locationServicesEnabled]) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"GPS未开启" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; }
5、请求数据
//实例化 self.locationManager = [[CLLocationManager alloc] init]; //GPS精确度 kCLLocationAccuracyBestForNavigation 导航级别(Best 最精确定位)(HundredMeters 百米级)(Kilometer 千米级)(ThreeKilometers 3千米级)
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; //设置距离过滤, 移动多少距离触发新的位置事件 [self.locationManager setDistanceFilter:100.f]; //设置响应的delegate self.locationManager.delegate = self;
6、为获取位置做好准备后,就可以开始定位
//开启定位服务 [self.locationManager startUpdatingLocation];
7、CLLocationManager将根据指定的参数在需要时利用GPS和/或Wi-Fi确定当前的位置。应实现两个委托方法,它们分别处理如下情形:位置管理器更新了当前位置或无法更新当前位置。
获取位置后,将调用:
//获取到位置点 -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ NSLog(@"%@", locations.lastObject); //位置管理器通过数组locations提供多个位置,其中最后一个是最新的位置。
}
无法更新当前位置将调用 :
//失败的时候 -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{ NSLog(@"%@", error); }
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ CLLocation *lastLocation = [locations lastObject]; if(lastLocation.horizontalAccuracy < 0 || lastLocation.horizontalAccu racy > 1000){
return;
}
NSLog(@">>>>%@",locations.lastObject); }
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{ [self.locationManager stopUpdatingLocation];
}
位置管理器委托可监控航向的变化,这很有用。可使用这些信息在地图上标出用户的前进路线 相对于正确路线的偏差。要获取航向信息,需要让位置管理器对其进行监视。还可设置⼀个可选的筛选器,这样航向变化小于指定的度数,就不会获取更新。
CLLocationDegrees degreesFilter = 2.0; if([CLLocationManager headingAvailable]) { [self.locationManager setHeadingFilter:degreesFilter]; [self.locationManager startUpdatingHeading]; }
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLH eading *)newHeading{ NSLog(@"new heading, magnetic%@",newHeading.magneticHeading); }
8、分析理解位置数据
CLLocationCoordinate2D coord = lastLocation.coordinate; NSLog(@"Locationlat/long: %f,%f",coord.latitude, coord.longitude);
CLLocationAccuracy horizontalAccuracy = lastLocation.horizontalAccuracy; NSLog(@"Horizontal accuracy: %f meters",horizontalAccuracy);
CLLocationDistance altitude = lastLocation.altitude; NSLog(@"Location altitude: %f meters",altitude); CLLocationAccuracy verticalAccuracy = lastLocation.verticalAccuracy; NSLog(@"Vertical accuracy: %f meters",verticalAccuracy);
9、重大位置变化通知
//开启 [self.locationManager startMonitoringSignificantLocationChanges]; //停⽌ [self.locationManager stopMonitoringSignificantLocationChanges];
10、使用GPX文件进行位置测试
<?xml version="1.0"?> <gpx version="1.1" creator="Xcode"> <wpt lat="37.331705" lon="-122.030237"></wpt> </gpx>
二、显示地图
1、配置和定制MKMapKit
//通过UISegmentedControl切换地图的区域 - (IBAction)mapTypeSelectionChanged:(id)sender {
UISegmentedControl *mapSelection = (UISegmentedControl *)sender; switch (mapSelection.selectedSegmentIndex) { case 0: [self.mapView setMapType:MKMapTypeStandard]; break;
case 1: [self.mapView setMapType:MKMapTypeSatellite]; break;
case 2: [self.mapView setMapType:MKMapTypeHybrid]; break; default: break; } }
//区域的中心点 CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(34.78, 113.68); //设置经纬度的跨度 MKCoordinateSpan span = MKCoordinateSpanMake(0.03, 0.03); //地图显示的区域 MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span); //设置地图显示区域 [self.mapView setRegion:region];
2、相应用户交互
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ MKCoordinateRegion newRegion = [mapView region]; CLLocationCoordinate2D center = newRegion.center; MKCoordinateSpan span = newRegion.span; NSLog(@"New map region center: <%f/%f>, span: <%f/%f>",center.latitude,center.longitude,span.latitudeDelta,span.longitudeDelta); }
三、地图注释和覆盖层
1、添加注释
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ //当前的最准确的位置点 CLLocation *location = locations.lastObject; //把当前位置作为注释添加上 MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; //位置指定为当前位置 annotation.coordinate = location.coordinate; annotation.title = @"你好"; annotation.subtitle = @"这是银行"; }
删除注释
 [self.mapView removeAnnotations:self.mapView.annotations];
自定义注释
//遵守MKAnnotation协议的对象,可以作为注释 @interface LEAnnotation : NSObject<MKAnnotation> //其隐性产生了一个get/set方法 @property(nonatomic)CLLocationCoordinate2D coordinate;
//在mapView文件
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
if ([annotation isKindOfClass:[LEAnnotation class]]) {
static NSString *Identifier = @"QYAnnotation";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:Identifier];
if (!annotationView) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:Identifier];
}
annotationView.annotation = annotation;
annotationView.image = [UIImage imageNamed:@"currentlocation"];
return annotationView;
}
return nil;
}
2、可拖拽的注释视图
3、使用地图覆盖层
添加覆盖层
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ CLLocation *location = locations.lastObject; //经过的位置点保存 [self.allLocation addObject:location]; //mkmappoint数组 MKMapPoint *mapArray = malloc(sizeof(MKMapPoint)*self.allLocation.count); for (int i = 0; i < self.allLocation.count; i++) { CLLocation *location = self.allLocation[i]; mapArray[i] = MKMapPointForCoordinate(location.coordinate); } //曲线覆盖层 MKPolyline *polyline = [MKPolyline polylineWithPoints:mapArray count:self.allLocation.count]; free(mapArray); //添加覆盖层 [self.mapView addOverlay:polyline]; }
当地图需要显示地图覆盖层的时候, 地图视图将调用委托⽅法mapView:viewForOverlay:,这个方法创建⼀个覆盖层视图,供地图进行显示。有三种形式:圆圈、多边形、和折线;也可自定义形状和覆盖层。
//返回覆盖层视图 -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{ if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolyline *line = (MKPolyline *)overlay; //覆盖层视图,曲线 MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:line]; renderer.lineWidth = 3.f; renderer.strokeColor = [UIColor blueColor]; //返回覆盖层 return renderer; } return nil; }