核心定位和地图的相关功能

来源:互联网 发布:全国各省经纬度数据 编辑:程序博客网 时间:2024/05/01 23:42

在iOS的应用中,有很多的应用都是使用了核心定位功能和地图的相关功能!

在实际开发中,也有很多相关的针对地图和定位来做的第三方插件!比如:百度地图。
关于第三方地图和定位插件,也是利用iOS中的相关API做的扩展和整合。具体,使用第三方的插件,就需要了解它们的API。

今天了解的就是iOS原始的核心定位和地图API!

什么是核心定位和地图

CoreLocation 以及 Map 框架包通常能给我们的应用程序添加定位和地图相关的服务。
CoreLocation 框架包通常是使用硬件设备来进行定位服务的,Map框架包通常能够使你的应用程序做一些地图展示与交互的相关功能。 

iOS将这两个功能封装到了两个库中。当然,我们需要在项目中引入该库,才能享受相应的服务。
这两个库分别是:

核心定位: #import

地图: #import


一、添加一个简单的地图视图

*.h文件

#import

#import

#import


@interface MoreViewController :UIViewController<</span>MKMapViewDelegate,CLLocationManagerDelegate>{


}

@property (nonatomic,strong)MKMapView *myMapView;


@end



*.m文件

-(void)viewDidLoad

{

   [superviewDidLoad];

   self.view.backgroundColor= [UIColor whiteColor];

    

   // 初始化MKMapView

   self.myMapView=[[MKMapView alloc]initWithFrame:self.view.bounds];

   self.myMapView.mapType= MKMapTypeHybrid;

   [self.myMapView setDelegate:self];

    

   self.myMapView.autoresizingMask= UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

    [self.viewaddSubview:self.myMapView];

    

    

  //返回用户是否开启了设备上的定位服务功能

   if([CLLocationManagerlocationServicesEnabled]){

      self.myLocationManager = [[CLLocationManageralloc] init];

       [self.myLocationManagersetDelegate:self];

       [self.myLocationManagersetPurpose:@"一些提示信息,告诉用户要开启定位服务功能"];

       

       // 开始更新地理位置,并根据更新结果执行CLLocationManagerDelegate方法

       [self.myLocationManagerstartUpdatingLocation];

    } else {

       

       NSLog(@"设备上的定位服务功能未开启!");

    }

      

}


说明:

在VC中,我们实现了两个协议,来捕捉相应的事件:
MKMapViewDelegate:关于地图的相关协议,定义了地图相关的协议方法。
CLLocationManagerDelegate:关于核心定位的相关协议。
这两个协议有很多方法,慢慢来体会吧。

二、为地图定义锚点

为了更好的封装性,我们自定义了一个锚点的自定义类,来控制锚点。
忽然有点迷茫,为什么要自定义锚点类呢?

@interface MyAnnotation : NSObject<</span>MKAnnotation>

因为MKAnnotation协议中的属性都是只读的!我们要方便的设置,就必须要覆盖MKAnnotation协议中的属性。

*.h文件

#import

#import


@interface MyAnnotation :NSObject<<span style="color:#743fa4">MKAnnotation>{


}


//特别要注意这个参数需要标示为只读类型的。因为MKAnnotation这个协议中定义的 Coordinate也是只读类型的。

@property (nonatomic,readonly)CLLocationCoordinate2D coordinate;

@property (nonatomic,copy, readonly)NSString *title;

@property (nonatomic,copy, readonly)NSString *subtitle;

 

@property (nonatomic, unsafe_unretained)MKPinAnnotationColor pinColor;// 气泡的颜色


// 初始化坐标(Coordinate

-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinatestitle:(NSString *)paramTitlesubTitle:(NSString*)paramSubTitle;

@end


*.m文件

#import "MyAnnotation.h"


@implementation MyAnnotation

@synthesize coordinate;

@synthesize title;

@synthesize subtitle;

 

@synthesize pinColor;


-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinatestitle:(NSString *)paramTitlesubTitle:(NSString*)paramSubTitle{

    

    self = [super init];

    if (self != nil){

      coordinate =paramCoordinates;

      title =paramTitle;

      subtitle =paramSubTitle;

 

    pinColor= MKPinAnnotationColorGreen;//定义默认颜色

    }

   return(self);

}


@end


这样,我们就能够调用我们自定义的锚点类来进行锚点的添加!

贴:

#pragma mark - CLLocationManagerDelegate 定位服务


//当获得了新的位置时,调用该方法

-(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation *)newLocationfromLocation:(CLLocation *)oldLocation{


    NSLog(@"Latitude = %f", newLocation.coordinate.latitude);

    NSLog(@"Longitude = %f",newLocation.coordinate.longitude);

    

   // 定义一个2D坐标

   CLLocationCoordinate2Dlocation=CLLocationCoordinate2DMake(newLocation.coordinate.latitude,newLocation.coordinate.longitude);

    

  //初始化锚点,根据坐标,标题,副标题

    MyAnnotation *annotation =[[MyAnnotation alloc]initWithCoordinates:location

                                                       title:@"My Title"

                                                     subTitle:@"My Sub Title"];


   // 为地图增加锚点

    [self.myMapViewaddAnnotation:annotation];


}


//当无法获得位置时,调用该方法

-(void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError *)error{


    NSLog(@"无法获取经纬度!");

}


#pragma mark - MKMapViewDelegate


//当地图界面将要加载的时候会调用该方法

-(void)mapViewWillStartLoadingMap:(MKMapView*)mapView{

    

   NSLog(@"mapViewWillStartLoadingMap");


}


三、为地图定义不同颜色的锚点

原来,我也觉的挺复杂的。或者是什么其他的特殊方式。
但是,实际用了,感觉原理跟TableView中的返回Cell的代理方法:

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath


是一个尿性的!对,原理一样啊!

也就是实现MKMapViewDelegate协议的mapView方法:

-(MKAnnotationView *)mapView:(MKMapView *)mapViewviewForAnnotation:(id)annotation

多的所以也不解释了!

贴:

//返回锚点(大头针)的View,根据坐标信息

-(MKAnnotationView*)mapView:(MKMapView *)mapViewviewForAnnotation:(id)annotation{

    MKAnnotationView *result =nil;

    if ([annotation isKindOfClass:[MyAnnotation class]] ==NO){

      returnresult;

    }

    if ([mapView isEqual:self.myMapView] ==NO){

      returnresult;

    }

    MyAnnotation *senderAnnotation = (MyAnnotation*)annotation;

    

  //获得锚点视图的颜色标识符

   // 重用MKPinAnnotationView(跟重用TableViewCell一个道理)

    

   NSString *pinReusableIdentifier =@"myAnnotation";

    

    MKPinAnnotationView*annotationView =(MKPinAnnotationView *) [mapViewdequeueReusableAnnotationViewWithIdentifier:pinReusableIdentifier];

    if (annotationView == nil){

       

       annotationView = [[MKPinAnnotationView alloc]initWithAnnotation:senderAnnotationreuseIdentifier:pinReusableIdentifier];

       [annotationView setCanShowCallout:YES];

    }


    annotationView.pinColor =senderAnnotation.pinColor;

    result = annotationView;

    return result;

}


四、通过地理坐标(经纬度)得到地址信息

当我们得到了一组经纬度数据,并且想把这组数据解析出来得到一个实在的地理位置名称。 
通过一组经纬度数据得到一个实在的地理位置数据,我们通常称之为逆向地理编码。 

我们使用CLGeocoder类可以来完成这项任务!

贴:

#pragma mark - CLLocationManagerDelegate 定位服务


//当获得了新的位置时,调用该方法

-(void)locationManager:(CLLocationManager *)managerdidUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation *)oldLocation{


    NSLog(@"Latitude = %f", newLocation.coordinate.latitude);

    NSLog(@"Longitude = %f", newLocation.coordinate.longitude);

    

  // 创建一个定位对象

    CLLocation *thelocation = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude

                                               longitude:newLocation.coordinate.longitude];

    

  //初始化一个反向地理编码对象

    self.myGeocoder = [[CLGeocoderalloc] init];

  //根据给定的经纬度来得到相应的地址信息

    [self.myGeocoderreverseGeocodeLocation:thelocationcompletionHandler:^(NSArray*placemarks,NSError *error){

      if (error ==nil&& [placemarkscount] > 0){

          

          // CLPlacemark存储着相应的地址数据

          CLPlacemark *placemark =[placemarksobjectAtIndex:0];


          NSLog(@"Country = %@", placemark.country);

          NSLog(@"Postal Code = %@",placemark.postalCode);

          NSLog(@"Locality = %@",placemark.locality);

       }

      elseif (error ==nil &&[placemarks count] ==0){

          NSLog(@"No results werereturned.");

       }

      elseif (error !=nil){

          NSLog(@"An error occurred =%@", error); }

    }];


}


有几点需要说明mark一下:

CLLocation:标识一个物理坐标对象。可以存储经纬度、海拔等信息。
CLGeocoder:这是一个提供物理地址(经纬度)到真实地址的转换的服务。换算出来的信息一般包括:国家、城市、州、街道等信息。而且,这个类需要基于联网状态下才能工作。因为数据都存储在苹果的数据库中。你懂的。

-(void)reverseGeocodeLocation:(CLLocation *)locationcompletionHandler:(CLGeocodeCompletionHandler)completionHandler方法:

用来转换地理坐标到真实地址的方法。

location:要转换的地址坐标

completionHandler:一个Block,请求返回时调用

在看一下CLGeocodeCompletionHandler这个Block的方法签名。

typedefvoid(^CLGeocodeCompletionHandler)(NSArray *placemarks,NSError *error);

placemarks:返回查询的地理信息

error:是否成功



五、通过地址信息得到地理坐标(经纬度)

当然,我们应该想到,地理坐标与地址信息之间应该能够互相转化。

反向地理编码是通过一组经纬度数据的到一个实在的地理位置名称。同样我们可以使用地理编码通过一个地理名称得到一组经纬度数据。 

CLGeocoder类可以来完成这项任务!

 

NSString *oreillyAddress =@"1005 Gravenstein HighwayNorth, Sebastopol, CA 95472, USA";

   self.myGeocoder = [[CLGeocoderalloc] init];

   [self.myGeocodergeocodeAddressString:oreillyAddresscompletionHandler:^(NSArray*placemarks,NSError *error){

       

       if ([placemarkscount] > 0 && error==nil){

           NSLog(@"Found %lu placemark(s).",(unsignedlong)[placemarks count]);

           CLPlacemark *firstPlacemark = [placemarksobjectAtIndex:0];

           NSLog(@"Longitude = %f",firstPlacemark.location.coordinate.longitude);

           NSLog(@"Latitude = %f",firstPlacemark.location.coordinate.latitude);

       

       elseif ([placemarks count] ==0 &&

               error ==nil){

          NSLog(@"Found no placemarks.");

        }

       elseif (error != nil){

          NSLog(@"An error occurred = %@", error);

        }

        }];