专业术语  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];
为什么在这里CLLocationManager实例对象必须保存? 
在 iOS8 中需要专门作出申请,首先在info.plist中添加key
NSLocationWhenInUseUsageDescription 或者 NSLocationAlwaysUsageDescription 申请时给用户的提示的文字信息作为key的内容。 
 
 
在authorizationStatus状态是 kCLAuthorizationStatusNotDetermined 时: 
    //授权状态
    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);
}
位置管理器可能通过数组locations提供多个位置,其中最后一个是最新的的位置。位置管理器还可能在没有开始获取位置时,就快速返回GPS检测到的最后位置;这种情况下,如果GPS已关闭且设备发⽣了移动,返回的位置将很不准确。所以要检查位置的精确度:为负值或者精确度过差,放弃这些点。如果返回的位置相当精确,就可以使用该位置点。在逐步确定准确位置期间,位置管理器可能调用这个方法多次,编写这个方法时必须考虑到这一点。 

 

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *lastLocation = [locations lastObject];
  if(lastLocation.horizontalAccuracy < 0 || lastLocation.horizontalAccu
  racy > 1000){

    return;
  }    
  NSLog(
@">>>>%@",locations.lastObject); }
如果位置管理器未能获取位置,它将调用 locationManager:didFailWithError: 导致错误的原因可能是未得到用户的许可,也可能是由于GPS或Wi-Fi不可⽤。发生错误时,通常要停⽌位置管理器停止更新当前位置并处理错误。 
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    [self.locationManager stopUpdatingLocation];
}

 位置管理器委托可监控航向的变化,这很有用。可使用这些信息在地图上标出用户的前进路线 相对于正确路线的偏差。要获取航向信息,需要让位置管理器对其进行监视。还可设置⼀个可选的筛选器,这样航向变化小于指定的度数,就不会获取更新。

CLLocationDegrees degreesFilter = 2.0;
if([CLLocationManager headingAvailable])
{
  [self.locationManager setHeadingFilter:degreesFilter];
  [self.locationManager startUpdatingHeading];
}
发⽣生航向变化事件时,将调⽤用委托⽅方法locationManager:didUpdateHeading: 
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLH
eading *)newHeading{
  NSLog(@"new heading, magnetic%@",newHeading.magneticHeading);
}

8、分析理解位置数据

位置管理器返回的位置是用CLLocation实例表⽰的。CLLocation包含多项有关位置的重要信息,首先是CLLocationCoordinate2D表示经度和纬度。 
CLLocationCoordinate2D coord = lastLocation.coordinate; 
NSLog(@"Locationlat/long: %f,%f",coord.latitude, coord.longitude);
作为经度和纬度的补充,还有⽔水平精度,它⽤用CLLocationDistance或⽶米数表⽰示。⽔水平精度指的 是实际位置与返回的坐标之间的距离在指定⽶米数之内。  
CLLocationAccuracy horizontalAccuracy = lastLocation.horizontalAccuracy;
NSLog(@"Horizontal accuracy: %f meters",horizontalAccuracy);
CLLocation 还提供了当前位置的海拔和垂直精度(单位为⽶米);如果设备没有GPS,返回的海拔 将为零,⽽而垂直精度为-1。 
CLLocationDistance altitude = lastLocation.altitude;
NSLog(@"Location altitude: %f meters",altitude);
CLLocationAccuracy verticalAccuracy = lastLocation.verticalAccuracy;
NSLog(@"Vertical accuracy: %f meters",verticalAccuracy);

9、重大位置变化通知

Apple强烈建议应用在获取位置后停止位置更新,以延长电池的续航时间 
通常,在设备位置变化超过500米或更换了连接的基站时,将发出通知。另外仅当最后一次通知 是在5分钟之前时,才会发送新的通知。
位置更新时间被交给委托⽅方法: locationManager:didUpdateLocations:进⾏行处理。 
//开启
[self.locationManager startMonitoringSignificantLocationChanges];
//停⽌
[self.locationManager stopMonitoringSignificantLocationChanges];

10、使用GPX文件进行位置测试

GPX文件是GPS交换格式文档,它使用XML格式,可⽤户在设备和GPS之间交换信息。在调试模式下,Xcode可使⽤GPX文件定义的“航点”来设置iOS 模拟器或设备的当前位置。
并且每个文件可以添加多个。 
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode"> 
    <wpt lat="37.331705" lon="-122.030237"></wpt>
</gpx>

二、显示地图

MapKit 框架为ios提供了地图用户界面功能,其中的基本类型是MKMapView,它显示地图、处理用户与地图的交互以及管理标注(像⼤头针)和覆盖层(如路线图或突出区域)。 

1、配置和定制MKMapKit

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、相应用户交互

可给MkMapView指定委托,以便对⽤户与地图互交做出响应。⽤户与地图的交互包括平移和放缩、拖拽注释(annotation)以及用户轻按标注(callout)时进行响应。 
⽤户平移或放缩地图时,将调用委托⽅法mapView:regionWillChangeAnimated:和 mapView:regionDidChangeAnimated:
如何获取新的地图区域:
- (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、添加注释

任何对象都可作为地图视图的注释,前提条件是实现了MkAnnotation协议。Apple建议注释对象 应该是轻量级的,因为对于添加的每个注释,地图视图都将包含一个指向它的引用;
另外,注释太多可能影响地图的滚动和放缩性能。如果注释非常简单,可使⽤MKPointAnnotation类 (UIKit提供的已经实现了MkAnnotation协议)。 
-(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,类必须实现属性coordinate,地图视图将使用这个属性确定注释放在地图的什么地方。属性coordinate获取方法返回一个CLLocationCoordinate2D,同时要存贮其相应的经纬度。
//遵守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、可拖拽的注释视图

可拖拽的注释视图很有用,它让用户能够再地图上指定地点。通过设置属性draggable设置为 YES, 让注释视图是可拖拽的。
通过地图视图的委托方法, mapView:annotationView:didChangeDragState:fromOldState:,可以更详细的了解⽤户是如何 拖拽注释视图的。 

3、使用地图覆盖层

地图覆盖层类似于地图注释,可以是任何实现了协议MKOverlay的对象,⽽地图视图委托将负责提供与地图覆盖层相关联的视图。
地图覆盖层不同于注释的地方在于,它们不仅可以表⽰示 点,还可以表⽰示线段和形状。因此非常适合⽤于再地图上表示路线或兴趣的区域。 

添加覆盖层

-(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;
}

 

 

 

 

 

 

 

 



 

 

 

 

posted on 2015-10-12 14:09  怡情_老二  阅读(400)  评论(0编辑  收藏  举报