iOS_mapKit与Core Location

目  录:
一、使用MKMap控件
二、根据地址定位
三、在地图上添加锚点
 
  iOS从3.0版本开始提供了MapKit.frameword支持。该框架提供了一个可被嵌入到应用程序中的地图视图类MKMapView,该地图视图类包含一个可上下、左右滚动的地图视图,而且可以非常方便地在地图中添加定制消息,并可以将其嵌入到应用程序中,通过编程的方式设置地图的各种属性(包含当前地图显示的区域以及用户当前所在位置)。
  iOS从4.0开始,MapKit框架支持可拖动标注和定制覆盖层。可拖动标注允许开发者以编程的方式或用户交互方式来重定位某个标注的位置;覆盖层则可用于创建有多个点组成的复杂标注,这种覆盖层可用于创建公交路线、公园边界或气象信息(如雷达数据)等。
   现在很多的社交软件都引入了地图和定位功能,要想实现这2大功能,那就不得不学习其中的2个框架:MaKit和CoreLocation
  (1)CoreLocation框架可以使用硬件设备来进行定位服务
  (2)MapKit框架能够使应用程序做一些地图展示与交互的相关功能 
  iOS定位支持的3中模式:手机基站、WIFI、GPS
一、使用MKMapView控件
  MKMapView控件中位于MapKit.framework中,因此为了在iOS应用中使用该控件,需要完成两件事情:1,为该应用添加MapKit框架;2,在使用MKMapView及相关类的源文件中使用“#import<MapKit/MapKit.h>”导入MapKit.framework的头文件。本章绝大部分示例都使用了MKMapView,因此都需要执行上面两步操作。
  1.指定地图显示中心和显示区域
  为了控制地图显示指定区域,只要两步即可。
  1、创建一个MKCoordinateRegion结构体变量,该结构体变量包含center,span两个成员,其中center控制显示区域的中心,span控制显示区域的范围。
  2、将MKMapView的region属性设为制定的MKCoordinateRegion结构体变量。
  iOS中为开发者提供了以下三种地图类型,开发者可以通过设置MKMapView的mapViewType设置地图类型。
  (1)MKMapTypeStandard 普通地图
  (2)MKMapTypeSatellite 卫星云图 
  (3)MKMapTypeHybrid 普通地图覆盖于卫星云图之上
   2.在地图中使用大头针
  (1)通过MapView的addAnnotation方法可以添加一个大头针到地图上
  (2)通过MapView的addAnnotations方法可以添加多个大头针到地图上
    - (void)addAnnotation:(id <MKAnnotation>)annotation;
    说明:需要传入一个遵守了MKAnnotation协议的对象(下面代码中进行演示)
  不但如此还要实现MapView的代理方法
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *ID = @"anno";
    MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annoView == nil) {
        annoView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
        // 显示气泡
        annoView.canShowCallout = YES;
        // 设置绿色
        annoView.pinColor = MKPinAnnotationColorGreen;
    }
    
    return annoView;
}
  案例:显示指定区域的地图
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import "MyAnnotation.h"
@interface ViewController ()<MKMapViewDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;

@property (weak, nonatomic) IBOutlet UITextField *latitude;
@property (weak, nonatomic) IBOutlet UITextField *longitude;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //设置地图的显示风格
    self.mapView.mapType = MKMapTypeStandard;
    //设置地图可缩放
    self.mapView.zoomEnabled = YES;
    //设置地图可滚动
    self.mapView.scrollEnabled = YES;
    //设置地图可旋转
    self.mapView.rotateEnabled = YES;
    //设置显示用户显示位置
    self.mapView.showsUserLocation = YES;
    //为MKMapView设置delegate
    self.mapView.delegate = self;
//    [self locateToLatitude:23.12672 longtitude:113.395];
    NSLog(@"用户当前是否位于地图中:%d",self.mapView.userLocationVisible);
    
}
- (IBAction)goClicked:(UIButton *)sender
{
    //关闭两个文本框的虚拟键盘
//    [self.latitude resignFirstResponder];
//    [self.longitude resignFirstResponder];
    //经度
    NSString *latitudeStr = self.latitude.text;
    //纬度
    NSString *longtitudeStr = self.longitude.text;
    //如果用户输入的经度、纬度为空
    if (latitudeStr != nil && latitudeStr.length > 0
        && longtitudeStr!= nil && longtitudeStr.length > 0)
    {
        //设置经度、纬度
        [self locateToLatitude:latitudeStr.floatValue longtitude:longtitudeStr.floatValue];
    }
}
-(void)locateToLatitude:(CGFloat)latitude longtitude:(CGFloat)longitude
{
    //设置地图中的的经度、纬度
    CLLocationCoordinate2D center = {latitude,longitude};
    //也可以使用如下方式设置经度、纬度
    //center.latitude = latitude;
    //center.longitude = longitude;
    //设置地图显示的范围
    MKCoordinateSpan span;
    //地图显示范围越小,细节越清楚;
    span.latitudeDelta = 0.01;
    span.longitudeDelta = 0.01;
    //创建MKCoordinateRegion对象,该对象代表地图的显示中心和显示范围
    MKCoordinateRegion region = {center,span};
    //设置当前地图的显示中心和显示范围
    [self.mapView setRegion:region animated:YES];
    
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
    [self.mapView addGestureRecognizer:longPress];
}

-(void)longPress:(UILongPressGestureRecognizer *)sender
{
    CGPoint location = [sender locationInView:self.mapView];
    //转换经纬度
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
    // 创建标注
    MyAnnotation *annotation = [[MyAnnotation alloc]init];
    annotation.coordinate = coordinate;
    annotation.title = @"新的标注";
    annotation.subtitle = @"开发...";
    [self.mapView addAnnotation:annotation];
}
#pragma mark - mapView代理方法

#pragma mark 显示标注视图
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *annotationID = @"annotation";
    MKPinAnnotationView *view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:annotationID];
    if (!view)
    {
        view = [[MKPinAnnotationView alloc]init];
    }
    view.annotation = annotation;
//    view.leftCalloutAccessoryView
    view.pinColor = MKPinAnnotationColorGreen;
    view.canShowCallout = YES;
    return view;
}
#pragma mark 代理方法
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    
    CLLocationCoordinate2D coordinate = userLocation.location.coordinate;
    MKCoordinateSpan span = {0.001,0.001};
    MKCoordinateRegion region = {coordinate,span};
    //设置显示区域
    [self.mapView setRegion:region animated:YES];
    
    MyAnnotation *annotation = [[MyAnnotation alloc]init];
    annotation.coordinate = coordinate;
    annotation.title = @"中国";
    annotation.subtitle = @"好牛B的地方";
    //让地图显示标注的区域
    [self.mapView setCenterCoordinate:annotation.coordinate animated:YES];
    

}
//当MKMapView显示区域将要发生改变时激发该方法
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
    NSLog(@"地图控件的显示区域要发生改变");
}
//当MKMapView显示区域改变完成时激发该方法
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    NSLog(@"地图控件完成了改变");
}
//当地图控件MKMapView开始加载数据时激发该方法
-(void)mapViewWillStartLoadingMap:(MKMapView *)mapView
{
    NSLog(@"地图控件开始加载地图数据");
    //创建MKCoordinateRegion对象,该对象代表地图的显示中心和显示范围
    MKCoordinateRegion region = mapView.region;
    self.latitude.text = [NSString stringWithFormat:@"%f",region.center.latitude];
    self.longitude.text = [NSString stringWithFormat:@"%f",region.center.longitude];
    
}
//当MKMapView加载数据完成时激发该方法
-(void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
    NSLog(@"地图控件加载地图数据完成");
    NSLog(@"%@",mapView);
}
//当MKMapView加载数据失败时激发该方法
-(void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error
{
    NSLog(@"地图控件加载地图数据发生错误:错误信息:%@",error);
}
//当MKMapView开始渲染地图时激发该方法
-(void)mapViewWillStartRenderingMap:(MKMapView *)mapView
{
    NSLog(@"地图控件开始渲染地图");
}
//当MKMapView渲染地图完成时激发该方法
-(void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered
{
    NSLog(@"地图控件渲染完成");
}
@end

  MyAnnotation.h文件内容

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MyAnnotation : NSObject<MKAnnotation>
@property(copy,nonatomic)NSString *title;
@property(copy,nonatomic)NSString *subtitle;
@property(assign,nonatomic)CLLocationCoordinate2D coordinate;
@end

  程序运行结果如下:

  程序中还为MKMapView指定了delegate,因此该delegate将会响应地图位置改变、加载过程中的相关事件,所以大家可以看到Xcode的控制输出消息。

二、根据地址定位

  1.地址解析与反向地址解析

  地址解析:把普通用户能看懂的字符串地址转换为经度、纬度。

  反向地址解析:把经度、纬度转换成普通的字符串地址。

  iOS为地址解析提供了CLGeocoder工具类,该工具类提供了如下3种方法来进行地址解析和反向地址解析。

  -geocodeAddressString:completionHandler: :根据给定的字符串地址进行解析,解析将会得到该地址对应的经度、纬度信息。

  -geocodeAddressString:inRegion:completonHandler: :根据给定的字符串进行解析,解析将会得到该地址对应的经度、纬度信息。

  -reverseGeocodeLocation:completionHandler: :根据给定的经度、纬度地址方向解析得到字符串地址。

  一般来说:地址解析可能得到多个结果——这是因为全球完全可能有多个同名的地点;但反向地址解析一般只会得到一个结果——因为根据指定经度、纬度得到的地址通常是唯一的。

  2.根据地址定位

  根据地址定位的思路非常简单,只要如下两步即可。

  (1)使用CLGeocoder根据字符串地址得到该地址的经度、纬度。

  (2)根据解析得到的经度、纬度进行定位。

  

#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>
@property(strong,nonatomic)CLLocationManager *locationManager;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建定位管理器
    self.locationManager = [[CLLocationManager alloc]init];
    //获取用户授权
    [self.locationManager requestAlwaysAuthorization];
    
    //获取当前授权状态
    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
    if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse)
    {
        NSLog(@"授权通过");
    }
    else
    {
        NSLog(@"授权不通过");
    }
    //设置代理
    self.locationManager.delegate = self;
    //设置经度
    self.locationManager.desiredAccuracy =kCLLocationAccuracyBest;
    //开始定位
    [self.locationManager startUpdatingLocation];
}
#pragma mark - 定位管理器的代理方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
   // NSLog(@"%@",locations);
    //取出位置信息
    CLLocation *location = [locations lastObject];
    
    //创建地理信息编解码对象
    CLGeocoder *geoCoder = [[CLGeocoder alloc]init];
    
    //转换位置信息
    [geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
//        NSLog(@"%@",placemarks[0]);
        CLPlacemark *placeMark = placemarks[0];
        NSLog(@"%@%@",placeMark.country,placeMark.locality);
    }];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"%@",error);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CLGeocoder *geoCoder = [[CLGeocoder alloc]init];
    [geoCoder geocodeAddressString:@"西三旗" completionHandler:^(NSArray *placemarks, NSError *error) {
        if ([placemarks count] == 0) {
            NSLog(@"没有找到相应的地理信息");
        }
        else
        {
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            //NSLog(@"%@",placeMark);
            // NSLog(@"%f,%f",placeMark.location.coordinate.latitude,placeMark.location.coordinate.longitude);
            
            MKMapItem *mapItem1 = [[MKMapItem alloc]initWithPlacemark:(MKPlacemark*)placemark];
            [geoCoder geocodeAddressString:@"八达岭长城" completionHandler:^(NSArray *placemarks, NSError *error) {
                MKMapItem *mapItem2 = [[MKMapItem alloc]initWithPlacemark:(MKPlacemark*)placemarks[0]];
                //调用系统地图打开一个位置
                [MKMapItem openMapsWithItems:@[mapItem1,mapItem2] launchOptions:nil];
            }];
        }
    }];
}
@end

三、在地图上添加锚点

  1.添加简单地锚点

  对于iOS的地图而言,添加锚点只要调用MKMapView的-(void)addAnnotation:(id<MKAnnotation>)annotation方法即可,每调用一次,就像地图添加一个锚点。MKAnnotation是一个协议,该协议中定义了3个属性,用于设置和返回锚点的信息。

  - coordinate:用于设置和返回锚点的位置。该属性值必须是一个CLLocationCoordinate2D结构体变量,封装了经度、纬度信息。

  - title:用于设置和返回锚点的标题。

  - subtitle:用于设置和返回锚点的副标题。

  2.添加自定义锚点

  锚点由两部分组成。

  锚点信息:锚点信息包括锚点的位置、标题、副标题等信息,这些信息有MKAnnotation对象代表。

  锚点控件:锚点控件决定地图上显示的锚点外观,包括锚点的图片等。

  iOS为锚点控件提供了MKAnnotationView和MKPinAnnotationView,其中MKPinAnnotationView是MKAnnotationView的子类,而MKAnnotationView继承了UIView——也就是说,它只是一个可视化的UI控件。

  为定制地图上的锚点,需要完成如下两步。

  1.为MKMapView指定delegate对象。

  2.重写delegatede-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation方法,该方法的返回值将作为地图上的锚点控件。

  案例:在图上添加锚点

#import "ViewController.h"
#import <MapKit/MapKit.h>
#import "MyAnnoation.h"
@interface ViewController ()<MKMapViewDelegate>
@property(strong,nonatomic)MKMapView *mapView;

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建mapView
    self.mapView = [[MKMapView alloc]initWithFrame:self.view.frame];
    //设置地图的类型
    self.mapView.mapType = MKMapTypeStandard;
    [self.view addSubview:self.mapView];
    
    self.mapView.delegate = self;
    
    //创建标注
    MyAnnoation *annoation = [[MyAnnoation alloc]init];
    annoation.coordinate= CLLocationCoordinate2DMake(40, 100);
    annoation.title = @"中国";
    annoation.subtitle = @"好牛B的地方";
    //添加标注
    [self.mapView addAnnotation:annoation];
    
    //让地图显示标注的区域
    [self.mapView setCenterCoordinate:annoation.coordinate animated:YES];
    
    //添加手势
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
    [self.mapView addGestureRecognizer:longPress];
}
-(void)longPress:(UILongPressGestureRecognizer *)sender
{

    //获取当前位置
    CGPoint location = [sender locationInView:self.view];
    //转换经纬度
    CLLocationCoordinate2D coordinate =[self.mapView convertPoint:location toCoordinateFromView:self.mapView];
    //创建标注
    MyAnnoation *annotation = [[MyAnnoation alloc]init];
    annotation.coordinate = coordinate;
    annotation.title = @"新的标注";
    annotation.subtitle = @"待开发。。";
    //添加标注
    [self.mapView addAnnotation:annotation];
    
}
#pragma mark - mapView代理方法
#pragma mark 显示标注视图
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *annotationID =@"annotation";
    //先从重用队列中去找
    MKPinAnnotationView *view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:annotationID];
    //如果找不到,自己创建
    if (!view)
    {
        view = [[MKPinAnnotationView alloc]init];
    }
    //设置属性
    view.annotation = annotation;
    view.canShowCallout = YES;//显示气泡视图
    view.pinColor = MKPinAnnotationColorPurple;//设置大头针颜色
    //显示图片(这种方式设置图片会取代大头针)
    view.image  = [UIImage imageNamed:@"0.png"];
    //设置气泡的辅助视图(显示图片)
    view.leftCalloutAccessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"0.png"]];
    return view;
}
#pragma mark 选中了标注后的处理

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"选中了标注");
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"取消了标注");
}
@end

 

全部评论

相关推荐

04-11 00:51
已编辑
门头沟学院 Java
先说一下楼主的情况:双非本大三,两段实习,javaer,想要找一个暑期大厂offer,努力了两个月,三月份每天的状态就是算法,八股,项目,四月份更是一个面试没有,最终还是没有结果,心碎了一地。期间面了一些中小厂,大厂只有腾讯约面,其他大厂都投了一遍,但是还是石沉大海。再看一下楼主的面试结果吧,就不说ttl了腾讯s3:三面挂csig:一面挂teg:三面挂wxg:一面挂没错,面了八次腾讯,两次三面挂,当时真的心都碎了。其他中小厂都有面,有的没过,有的oc,但是都没有去。其他大厂投了简历,但是不是简历挂,就是测评挂,都说今年行情好很多,各大厂都扩招,可是问题出在那里呢?学历背景吗?实习经历吗?还是简历不够好看?依稀记得,从年初七就离开了家里,回到学校,早早准备面试,当时自己认为凭借着自己的两段实习经历,以及大二就开始准备的八股算法,拿大厂offer不是问题,但是还是不敢放松,回校的状态每天就是算法,八股,还有查看各种招聘信息,想着尽早投机会多,但是事实证明,投的早,不如投的刚刚好。当时想着,先投一些中小厂开始面试,找找面试感觉,从2.10就开始有面试了,基本都是线下面试,面试的感觉都很不错,觉得自己的状态慢慢回来了,期间也有oc一些中小厂,但是自己的目标并不在此,只是想练一下手,遂拒。后面投了腾讯的暑期实习基地,不久就约面了,第一次面这么大的厂,多少有点紧张,好在运气还不错,遇到的面试官也比较好,一直干到了三面,期间看牛客有不少说一面就挂了的,感觉自己还是比较幸运的,但是没想到倒在了三面,一周后就挂了,伤心是有的,但是想到这才刚刚开始,还有很多机会,便继续准备下一次面试了,很快,被另外一个部门捞了,一进会议,面试官没开摄像头,看网上说没开摄像头很多都是kpi,但是自己给自己打气,认为面试官只是不方便开摄像头罢了,面完,感觉良好,没问什么很难得问题,基本都答出来了,算法两道也a了一道,感觉实习不会这么严格吧?还是过了一会挂了,因为这个?还是技术不太匹配?面试过程中说搞C++的,心想,搞c++的你面我干啥?唉,这时候有点气馁,然后就接下来半个月没有面试。这时已经是三月底了,看到牛客好多人都已经陆陆续续拿到了offer,看人家的面试准备也没那么早,有0实习的,有没刷算法的,有两个面的,,,唉,反正是一言难尽啊,感觉努力没有什么意义,面试多半是看面试官的感觉,主观性很大啊,只要你技术没有太大的问题。第三次面试腾讯,面试来的比较突然,期间已经有几天没看八股什么的了,临时看了一下之前自己做的面试笔记,但是面试却异常顺利,三天闯到了三面,自己也不敢相信,三面玩感觉也良好,脑子里不得不想着一些“offer结算画面”,但是过了一会查看流程显示“流程终止”,我?哎,当时真的有苦说不出啊,也是一晚没睡。后面就逐渐开始褪去大厂梦了,看着曾经跟自己交流的牛油,朋友,认识的人,觉得他们技术不太如你,算法刷的没你多,进了大厂,但是这又如何呢?能力强不强不是你了说了,面试官说了算。也逐渐知道,不是你能力好就可以了,还得有运气,运气,运气。这个过程太累了,和自己和解吧,不用非得大厂,找个合适一点的就好,放轻松一点。今天有点心事睡不着,闲着想写一些自己的面试过程,勿喷。附上一张面试的情况,公司就不方便透露了。
怒卷的斯科特:八分运气两分实力
点赞 评论 收藏
分享
05-12 17:00
门头沟学院 Java
king122:你的项目描述至少要分点呀,要实习的话,你的描述可以使用什么技术,实现了什么难点,达成了哪些数字指标,这个数字指标尽量是真实的,这样面试应该会多很多,就这样自己包装一下,包装不好可以找我,我有几个大厂最近做过的实习项目也可以包装一下
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务