iOS iOS 地图与定位开发系列教程

2022-09-17 14:03:54 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

iPhone SDK提供了三个类来管理位置信息:CLLocation CLLocationManager 和 CLLHeading(不常用)。除了使用GPS来获取当前的位置信息外,iPhone也可以基于WiFi基站和无线发射塔来获得位置信息。GPS的精度最高,可以精确到米级别,但是也最耗电。

1、CLLocation

CLLocation类代表一个位置信息,其中还包括了方向和速度。比如我在长安街188号以5公里/小时的速度往西走。CLLocation具有下面的属性和方法:

代码语言:javascript复制
@property  CLLocationCoordinate2D coordinate; //以经度和纬度表示的位置信息
@property CLLocationDistance altitude;  //海拔
@property CLLocationAccuracy horizontalAccuracy; //水平精度(如:精确到米)
@property CLLocationAccuracy verticalAccuracy; //垂直精度
@property CLLocationDirection course; //方向
@property CLLocationSpeed speed; //速度
-(NSDate *)timeStamp;
-(CLLocationDistance)distanceFromLocation:(CLLocation *)location;//两个位置之间的距离

2、CLLocationManager

CLLocationManager类管理和提供位置服务。它的属性和方法有:

代码语言:javascript复制
@property CLLocation *location; //位置
@property id<CLLocationManagerDelegate> delegate;
@property CLLocationDistance distanceFilter; //距离过滤,比如:500以内
@property CLlocationAccuracy verticalAccuracy; //垂直精度
-(void) startUpdatingLocation; //开始更新位置(比如:你在往某个地方走)
-(void)stopUpdatingLocation; //停止更新位置
-(void)startUpdatingHeading; //开始更新方向(比如:你改往东走)
-(void)stopUpdatingHeading; //停止更新方向

CLLocationManagerDelegate是一个委托类。你的应用程序需要使用这个委托类。

代码语言:javascript复制
//当用户改变位置的时候,CLLocationManager回调的方法
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;

//当用户改变方向的时候,所调用的方法
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLLHeading *)newHeading;

//当iPhone无法获得当前位置的信息时,所回调的方法是
-(void)locationManager: (CLLocationManager *)manager didFailLoadWithError:(NSError *)error;

下面我们来看一个位置类的基本步骤:

一、启动定位服务

代码语言:javascript复制
CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];

二、获得位置信息

代码语言:javascript复制
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation: (CLLocation *)oldLocation
{
NSTimeInterval howRecent = [newLocation.timestamp timeIntervalSinceNow];
if(howRecent < -10) return ; //离上次更新的时间少于10秒
if(newLocation.horizontalAccuracy > 100) return; //精度> 100米
//经度和纬度
double lat = newLocation.coordinate.latitude;
double lon = newLocation.coordinate.longitude;
}

三、获得方向信息(比如往南走)

代码语言:javascript复制
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
//获得方向
CLLocationDirection heading = newHeading .trueHeading;
}

四、停止定位

代码语言:javascript复制
[locManager stopUpdatingLocation];

你可以设置你想要的精度和距离过滤:

代码语言:javascript复制
locManager.desiredAccuracy = kLLocationAccuracyBest;
locManager.distanceFilter = 1000;

MapKit框架主要提供了四个功能: 1、显示地图; 2、CLLocation和地址之间的转换; 3、支持在地图上做标记(比如标记北京天安门广场); 4、 把一个位置解析成地址(比如我在水立方,想要知道确切的地址信息)。

MKMapView类主要是完成下述功能: 1、显示地图,比如:显示北京市的地图; 2、提供多种显示方式,比如标准地图格式,卫星地图等; 3、支持地图的放大缩小; 4、支持在地图上做标记,比如标记天安门广场; 5、在地图上显示手机所在的当前位置。

MKMapView类的属性有:

代码语言:javascript复制
@property MKCoordinateRegin region; //地图所显示的区域
@property CLLocationCoordinate2D centerCoordinate; //经度和纬度确定的中心位置
@property MKMapView mapType; //地图的显示类型,如:卫星地图
@property NSArray *annotations; //地图上的标记
@property MKUserLocation userLocation; //用户位置
@property id <MKMapViewDelegate>delegate; //委托类

装载地图时的回调方法有:

代码语言:javascript复制
-(void)mapViewWillStartLocationMap:(MKMapView *) mapView; //开始装载地图
-(void)mapViewDidFinishLocationMap:(MKMapView  *)mapView; //结束装载地图
-(void)mapVewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error; //装载失败

当位置发生转变时的回调方法:

代码语言:javascript复制
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated; //将要更改
-(void)mapView: (MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; //已经更改

MKPlacemark、MKUserLocation和MKReverseGeocoder

在地图上做标记是通过MKPlacemark类来完成的。这个类使用(符合)MKAnnotation协议。MKAnnotation包含了多个属性,如:位置(经纬度,CLLocationCoordinate2D类型)、文字标记信息(NSString类型)等。 MKPlacemark保存了位置(经纬度)和地址(字典类)之间的映射。下面是它的初始化方法:

代码语言:javascript复制
-(void)initWithCoordinate:(CLLocationCoordinate2D *)coordinate addressDictionary:(NSDictionary *)dictionary;

MKUserLocation就是指手机的当前位置,它是MKAnnotation的一个特别案例(因为MKAnnotation可以是地图上的任何标记,而MKUserLocation只是标记了地图上手机所在的当前位置)。这个类包含了多个属性:手机的位置(类型为CLLocation)、位置文字信息(类型为NSString)等。 MKPlacemark保存了位置(经纬度)和地址之间的映射。那么,有没有工具在这两者之间做转换呢?这就是MKRecerseGeocoder.给定一个位置信息,这个类可以返回相应的地址信息。MKReverseGeocoder的初始化方法为:

代码语言:javascript复制
-(void)initWithCoodinate:(CLLocationCoordinate2D)coordinate;

下面是MKReverseGeocoder常用的一些属性和方法:

代码语言:javascript复制
@property id <MKReverseGeocoderDelegate>delegate; //委托
-(void)start; //开始转换
-(void)cancel; //取消转换

回调的方法有:

代码语言:javascript复制
-(void)reverseGeocoder:(MKReverseGeocoder *) geocoded didFindPlacemark:(MKPlacemark *)placemark;  //转换成功
-(void)reverseGeocoder : (MKReverseGeocoder *)geocoded didFailWithError:(NSError *)error; //转换失败

iOS MKMapView 基础

综述

地图相关类前缀CL: Core Location。

一.定位

CLLocationManager

The CLLocationManager object is your entry point to the location service. 用于定位

构造方法

代码语言:javascript复制
- (CLLocationManager *)locationManager
{
    if (!_locationManager) {
        //判断定位功能是否打开
        if ([CLLocationManager locationServicesEnabled]) {
            _locationManager = [[CLLocationManager alloc]init];
            _locationManager.delegate = self;
            [_locationManager requestWhenInUseAuthorization];
            
            //设置寻址精度
            _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
            _locationManager.distanceFilter = 5.0;
            [_locationManager startUpdatingLocation];
        }
    }
    return _locationManager;
}

定位权限

代码语言:javascript复制
- (void)getUserLocationAuthorization{
    //判断当前设备定位服务是否打开
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"设备尚未打开定位服务");
    }
    
    //判断当前设备版本大于iOS8以后的话执行里面的方法
    if ([UIDevice currentDevice].systemVersion.floatValue >=8.0) {
        //当用户使用的时候授权
        [self.locationManager requestWhenInUseAuthorization];
    }
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        NSString *message = @"您的手机目前未开启定位服务,如欲开启定位服务,请至设定开启定位服务功能";
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"无法定位" message:message delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
        [alertView show];
    }
}

设置显示范围

遵循CLLocationManagerDelegate协议,实现代理方法

代码语言:javascript复制
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    [self.locationManager stopUpdatingHeading];
    //地址
    self.userLocation = [locations lastObject];
    //显示范围
    double latitudeSpan = fabs(self.latitude - self.userLocation.coordinate.latitude) * 3;
    double longitudeSpan = fabs(self.longitude - self.userLocation.coordinate.longitude) *3;
    
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeSpan, longitudeSpan);
    MKCoordinateRegion regoin = MKCoordinateRegionMake(self.userLocation.coordinate, span);
    [self.mapView setRegion:regoin animated:YES];
}

二.地图

初始化

代码语言:javascript复制
- (MKMapView *)mapView
{
    if (!_mapView) {
        _mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,0, kScreenWidth, kScreenHeight)];
        //设置用户的跟踪模式
        _mapView.userTrackingMode = MKUserTrackingModeFollow;
        //设置标准地图
        _mapView.mapType = MKMapTypeStandard;
        // 不显示罗盘和比例尺
        if (@available(iOS 9.0, *)) {
            _mapView.showsCompass = NO;
            _mapView.showsScale = NO;
        }
        // 开启定位
        _mapView.showsUserLocation = YES;
        _mapView.delegate = self;
        //初始位置及显示范围
        MKCoordinateSpan span=MKCoordinateSpanMake(0.021251, 0.016093);
        [_mapView setRegion:MKCoordinateRegionMake(self.mapView.userLocation.coordinate, span) animated:YES];
    }
    return _mapView;
}

设置覆盖物

代码语言:javascript复制
- (void)initCarPoint{
    //创建CLLocation 设置经纬度
    CLLocation *loc = [[CLLocation alloc]initWithLatitude:self.latitude longitude:self.longitude];
    CLLocationCoordinate2D coord = [loc coordinate];
    //创建标题
    NSString *titile = @"救护车";
    MSCarPoint *myPoint = [[MSCarPoint alloc] initWithCoordinate:coord andTitle:titile];
    //添加标注
    [self.mapView addAnnotation:myPoint];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    static NSString *placemarkIdentifier = @"PointAnnotation";
    if ([annotation isKindOfClass:[MSCarPoint class]]){
        MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:placemarkIdentifier];
        if([annotation.title isEqualToString:@"救护车"]){
            //救护车
            annotationView.image = [UIImage imageNamed:@"icon"];
        }
        return annotationView;
    }
    return nil;
}

重定位我的位置

代码语言:javascript复制
- (void)resetLocation:(id)sender {
    // 定位到我的位置
    [self.mapView setCenterCoordinate:_mapView.userLocation.coordinate animated:YES];
}

三.地理编码

CLGeocoder

CLGeocoder: 地理编码。 地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等) 反地理编码:根据给定的经纬度,获得具体的位置信息

CLPlacemark

CLPlacemark: 详细的地址位置信息,包括如下主要属性。 地理位置     @property (nonatomic, readonly) CLLocation *location; 区域       @property (nonatomic, readonly) CLRegion *region; 详细的地址信息 @property (nonatomic, readonly) NSDictionary *addressDictionary; 地址名称    @property (nonatomic, readonly) NSString *name; 城市      @property (nonatomic, readonly) NSString *locality;

CLLocation

CLLocation:地理位置

根据地名进行标注代码实例

代码语言:javascript复制
//初始化地理编码器
let coder = CLGeocoder()
//根据地名字符串返回CLPlacemark数组和error
coder.geocodeAddressString(area.name) { (placeMark, error) in
    //使用guard进行前置条件判断,为空时打印错误然后终止方法
    guard placeMark != nil else {
        print(error ?? "未知错误")
        return
    }
    //获取地理位置详细信息数组中第一个
    let place = placeMark?.first
    //初始化标注
    let annotation = MKPointAnnotation()
    //指定标注标题及副标题
    annotation.title = self.area.name
    annotation.subtitle = self.area.province
    
    //获取CLPlacemark中的CLLocation
    if let location = place?.location{
        //设置标注经纬度
        annotation.coordinate = location.coordinate
        //显示标注
        self.mapView.showAnnotations([annotation], animated: true)
        //选中标注
        self.mapView.selectAnnotation(annotation, animated: true)
    }
}

自定义图钉视图

遵循MKMapViewDelegate协议,实现如下代理方法。 - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; 代码如下。

代码语言:javascript复制
// MARK: - map delegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    //判断是否是用户位置
    if annotation is MKUserLocation {
        //如果是用户当前位置,终止方法
        return nil
    }
    //指定标注重用标识符
    let mapId = "myAnnotationId"
    //根据重用标识符获取标注视图(与cell重用原理类似)。 注:取出标注视图转为MKPinAnnotationView,自带图钉(只自定义左附加视图图片)
    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: mapId) as? MKPinAnnotationView
    //判断标注视图是否存在
    if annotationView == nil {
        //如果标注视图不存在,根据标注和标注重用标识符创建标注视图
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: mapId)
        annotationView?.canShowCallout = true
    }
    //设置自定义icon视图
    let iconView = UIImageView(frame: CGRect(x: 0, y: 0, width: 53, height: 53))
    iconView.image = UIImage(named: "dislike")
    //设置左附加视图图片
    annotationView?.leftCalloutAccessoryView = iconView
    
    //自定义图钉颜色 IOS9 
    annotationView?.pinTintColor = UIColor.blue
    
    //返回标注视图
    return annotationView
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/158816.html原文链接:https://javaforall.cn

0 人点赞