OC 技术 原生地图(源码)

OC 技术 原生地图(源码),第1张

一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希望未来技术之巅上有你们也有我。

CLLocationManager:定位对象的属性

属性注释
distanceFilter距离筛选器(米)
desiredAccuracy定位经度(枚举值)
allowsBackgroundLocationUpdates允许后台位置更新(>= iOS 9.0)

CLLocationManager:定位对象的方法

方法注释
requestWhenInUseAuthorization设置连续定位方法
startUpdatingLocation开始定位方法(实现代理方法可以获取定位)

CLLocation:定位对象的方法

方法注释
distanceFromLocation比较2个位置之间的距离比较的是直线距离

注意:获取定位之前。首先需要在info.plist里面,申请获取用户定位权限。

NSCameraUsageDescription
是否允许开启相机拍照以便选取证件图片
NSLocationWhenInUseUsageDescription
获取当前定位
NSPhotoLibraryUsageDescription
是否允许打开相册以便你选择要发送证件图片
获取当前定位(定位一次)

实例代码地址
获取当前定位只需要拿到当前的定位对应,初始化,遵守代理,实现它的代理方法就能够获取到到当前的定位了。
下面是定位的参考代码,直接复制就能够看到效果了。

#import "OncePositioningVC.h"
// 定位框架
#import 

@interface OncePositioningVC ()

//位置管理器
@property (nonatomic,strong)CLLocationManager *locationManager;

@end

@implementation OncePositioningVC

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  //1. 创建一个CLLocationManager对象
  self.locationManager = [CLLocationManager new];
  //2. 请求授权 --> iOS8以后需要授权并配置plist键值,NSLocationWhenInUseUsageDescription:授权需要填加的值,Localization native development region:en;
  //为了防止iOS7奔溃,需要做判断: 2种方式: 1.判断能否响应 2.判断系统版本
  //if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) { }
  if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    //当程序在前台,看见的时候调用
    [self.locationManager requestWhenInUseAuthorization];
  }
  //3. 设置代理-->来获取用户定位的数据
  self.locationManager.delegate = self;
  //4. 开始定位
  [self.locationManager startUpdatingLocation];
}

#pragma mark 定位的代理方法
/**
 当完成位置更新的时候调用
 locations: 位置信息数据
 此方法会频繁调用.非常耗电
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
  //逢简 22.81246197,113.15102071
  //locations : 包含了经纬度, 速度等信息
  NSLog(@"locations: %@", locations);
  //5. 停止定位( 如果不 停止定为就是持续定位)
  [self.locationManager stopUpdatingLocation];
  
}

@end

连续定位

实例代码地址

连续定位用于当用户的定位位置发生变化的时候就实时的更新当前的定位位置。

直接上代码

#import "ContinuedPositioningVC.h"
#import 

@interface ContinuedPositioningVC ()

@property (nonatomic,strong)CLLocationManager *locationManager;

@end

@implementation ContinuedPositioningVC
//持续定位
- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  //1. 创建一个CLLocationManager对象
  self.locationManager = [CLLocationManager new];
  //2. 请求授权 --> iOS8以后需要授权并配置plist键值
  if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [self.locationManager requestWhenInUseAuthorization];
 }
  //3. 设置代理-->来获取用户定位的数据
  self.locationManager.delegate = self;
  //4. 开始定位
  [self.locationManager startUpdatingLocation];
  /**
   持续定位:其实就是希望定位的时候,可以节省电量.
   距离筛选器:当用户发生一定的位置改变之后,再调用代理方法
  */
  //5.距离筛选器:单位米  -->主要是通过降低代理方法的调用频率,达到省电目的
  //Filter:筛选 /过滤
  // 如果设置了10,那么发生了10米以上的变化时才会调用
  self.locationManager.distanceFilter = 10;
  //6. 预期精准度:
  //desired: 期望/预期
  //Accuracy: 精准度
  /**
    手机中定位方法: GPS / WIFI /移动基站  /北斗(iPhone中没有)
    主要是通过GPS来定位: GPS是跟全球24颗卫星在进行通讯.可以通过减少计算量来达到省电的目的
   */
  /**
    精准度
    CLLocationAccuracy kCLLocationAccuracyBestForNavigation//最好的为导航
    CLLocationAccuracy kCLLocationAccuracyBest;//最好的
    CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;//10米
    CLLocationAccuracy kCLLocationAccuracyHundredMeters;//百米
    CLLocationAccuracy kCLLocationAccuracyKilometer;//1千米
    CLLocationAccuracy kCLLocationAccuracyThreeKilometers;3千米
    */
  self.locationManager.desiredAccuracy =kCLLocationAccuracyKilometer;
  //7. 比较2个位置之间的距离比较的是直线距离
  // 北京到西安的距离
  CLLocation *location1 = [[CLLocation alloc] initWithLatitude:40.06l longitude:116.39];
  CLLocation *location2 = [[CLLocation alloc] initWithLatitude:34.27l longitude:108.93];
  CLLocationDistance distance = [location1 distanceFromLocation:location2];
  NSLog(@"distance: %f",distance /1000);
  
}



#pragma mark 定位的代理方法
/**
 当完成位置更新的时候调用
 locations: 位置信息数据
 此方法会频繁调用.非常耗电
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
  // CLLocation: 位置对象
  CLLocation *location = locations.lastObject;
  //locations : 包含了经纬度, 速度等信息
  NSLog(@"locations: %@", location);
  //CLLocationCoordinate2D coordinate : 2D位置坐标:
  //CLLocationDegrees latitude : 纬度
  //CLLocationDegrees longitude : 经度
  //CLLocationDegrees: double值
  //方法
  //distanceFromLocation
  
}
@end
iOS9新特性: 临时获取后台定位

实例代码地址

直接上代码

#import "BackstagePositioningVC.h"
#import 

@interface BackstagePositioningVC ()

//位置管理器
@property (nonatomic,strong)CLLocationManager *locationManager;

@end

@implementation BackstagePositioningVC

- (void)viewDidLoad {
    [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  //1. 创建一个CLLocationManager对象
    self.locationManager = [CLLocationManager new];
  //2. 请求授权 --> iOS8以后需要授权并配置plist键值;NSLocationAlwaysUsageDescription:随便写
  // 请求授权这个步骤是在iOS8以后才出现的.如果iOS7之前直接调用会崩溃.
  //为了防止iOS7奔溃,需要做判断: 2种方式: 1.判断能否响应 2.判断系统版本
  //if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) { }
  if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    // 当用户使用时授权 :当程序能看见的时候,正在运行的时候
    [self.locationManager requestWhenInUseAuthorization];
    // 永久授权 :当程序后台运行 /锁屏界面都可以获取定位信息
    //[self.locationManager requestAlwaysAuthorization];
   }
  /**
   iOS9新特性: 临时获取后台定位
当使用了使用期间授权时,可以在需要后台定位的地方,添加allowsBackgroundLocationUpdates属性,并设置为YES.同时还需要打开后台定位模式 -->点击项目-->Capabilitys-->Background Modes-->勾选Location update
   不用设置永久定位,此时就可以进行临时获取后台定位信息,但是屏幕上会有蓝条信息显示
  */
  if ([UIDevice currentDevice].systemVersion.floatValue >=9.0) {
    //allowsBackgroundLocationUpdates : 允许后台位置更新
    self.locationManager.allowsBackgroundLocationUpdates = YES;
   }
  //3. 设置代理-->来获取用户定位的数据
  self.locationManager.delegate = self;
  //4. 开始定位
  [self.locationManager startUpdatingLocation];

}

#pragma mark 定位的代理方法
/**
 当完成位置更新的时候调用
 locations: 位置信息数据
 此方法会频繁调用.非常耗电
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
  //locations : 包含了经纬度, 速度等信息
  NSLog(@"locations: %@", locations);
}

@end
地理编码

实例代码地址

通过名称获取经纬度

#import "GeocodingVC.h"
#import 

@interface GeocodingVC ()


@end

@implementation GeocodingVC

- (void)viewDidLoad {
    [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  //1. 创建CLGeocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2. 调用地理编码方法
  //placemarks: 地标对象
  //CLPlacemark中有CLLocation(可以获得经纬度),region,街道名称,城市,州很多信息。
  [geocoder geocodeAddressString:@"广东省,佛山市,顺德区,杏坛镇,逢简" completionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) {
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      NSLog(@"解析出错");
      return;
      }
    //3.2 解析数据
    // 正地理编码,一个地名可能对应多个经纬度.所以,实际做的时候应该给用户一个列表选择
    // 咱们这里不做处理了
    for (CLPlacemark *placemark in placemarks) {
    //3.3 经纬度
     NSLog(@"la: %f, long: %f", placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);
      //3.4 详细地址 --name
      NSLog(@"name-%@",placemark.name);
      //NSLog(@"name: %@", placemark.name);
      NSLog(@"city: %@",placemark.locality);
      // 取城市的时候,locality有可能为空.为了避免取城市的时候程序崩溃,可以使用administrativeArea暂时代替一下
      NSLog(@"administrativeArea%@",placemark.administrativeArea);
    }
  }];
}

@end
反地理编码

实例代码地址

通过经纬度获取当前地址

#import "AntiGeocodingVC.h"
#import 

@interface AntiGeocodingVC ()

@end

@implementation AntiGeocodingVC

- (void)viewDidLoad {
    [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  //1. 创建Geocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2.1 创建位置对象
  CLLocation *location = [[CLLocation alloc] initWithLatitude:22.809787 longitude:113.154024];
  //2.2 调用反地理编码方法
  [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *_Nullable placemarks,NSError *_Nullable error) {
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      return;
    }
    //3.2 解析数据反地理编码,只会对应一个唯一的地址,所以不需要for循环
    CLPlacemark *placemark = placemarks.lastObject;
    
    //locality: 城市
    if (placemark.locality) {
      NSLog(@"城市-%@",placemark.locality);
     } else {
        //administrativeArea: 行政区域
       NSLog(@"行政区域-%@",placemark.administrativeArea);
     }
    
    }];

}

@end
显示地图

实例代码地址
下面代码的主要功能
1.地图的功能能够获取当前定位显示在地图上面
2.放大,缩小地图
3.点击搜索按键能够把周边的酒店检索出来

#import "MapViewVC.h"
#import 
#import 
#import 

//mapView的使用
@interface MapViewVC ()

@property (nonatomic,strong)CLLocationManager *mgr;
@property (nonatomic,strong) MKMapView *mapView;
@property (nonatomic,strong) UIButton *bigBtn;
@property (nonatomic,strong) UIButton *smallBtn;

@end

@implementation MapViewVC

- (void)viewDidLoad {
    [super viewDidLoad];

  //设置导航栏的文字按键
  UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"GO" style:UIBarButtonItemStylePlain target:self action:@selector(rightItemBtnClick)];
  //设置文字颜色
  [rightItem setTintColor:[UIColor redColor]];
  
  UIBarButtonItem *searchItem = [[UIBarButtonItem alloc] initWithTitle:@"Search" style:UIBarButtonItemStylePlain target:self action:@selector(searchItemBtnClick)];
  
  self.navigationItem.rightBarButtonItems = @[rightItem,searchItem];
  
  self.mapView = [[MKMapView alloc] init];
  self.mapView.addTo(self.view).makeCons(^{
    make.left.top.right.bottom.equal.view(self.view);
  });
  
  //1. 创建位置管理器并授权
  self.mgr = [CLLocationManager new];
  // 请求授权 --> 配置plist
  if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [self.mgr requestWhenInUseAuthorization];
  }
  //2. 显示用户位置
  //Tracking: 跟踪
  //userTrackingMode: 用户跟踪模式
  /**
    MKUserTrackingModeNone = 0, // the user's location is not followed
    MKUserTrackingModeFollow, // the map follows the user's location
    MKUserTrackingModeFollowWithHeading, // the map follows the user's location and heading
  */
  self.mapView.userTrackingMode = MKUserTrackingModeFollow;
  //3. 设置代理 --> 获取用户位置
  self.mapView.delegate =self;
  /**
    iOS9新特性 -显示交通状况 /显示比例尺 / 显示指南针
  */
  //1.显示交通状况
  self.mapView.showsTraffic =YES;
  //2.显示比例尺
  self.mapView.showsScale =YES;
  //3.显示指南针 (默认YES)
  self.mapView.showsCompass =NO;
  
  #pragma mark 放大地图
  self.bigBtn = [UIButton new];
  self.bigBtn.addTo(self.mapView).img(@"map_plus_normal").borderRadius(5).makeCons(^{
    make.width.height.equal.constants(50);
    make.right.equal.view(self.mapView).constants(-20);
    make.bottom.equal.view(self.mapView).constants(-20);
  }).onClick(^{
    //1. 将当前的显示跨度缩小一倍
    //region : 是当前地图显示的区域
    CGFloat latitude =self.mapView.region.span.latitudeDelta * 0.5;
    CGFloat longitude =self.mapView.region.span.longitudeDelta * 0.5;
    [self.mapView setRegion:MKCoordinateRegionMake(self.mapView.region.center,MKCoordinateSpanMake(latitude, longitude)) animated:YES];
  });
  
  #pragma mark 缩小地图
  self.smallBtn = [UIButton new];
  self.smallBtn.addTo(self.mapView).img(@"map_sign_normal").borderRadius(5).makeCons(^{
    make.width.height.equal.constants(50);
    make.left.equal.view(self.mapView).constants(20);
    make.bottom.equal.view(self.mapView).constants(-20);
  }).onClick(^{
    //1. 将当前的显示跨度放大一倍
    //region : 是当前地图显示的区域
    CGFloat latitude =self.mapView.region.span.latitudeDelta * 2;
    CGFloat longitude =self.mapView.region.span.longitudeDelta * 2;
    // 经纬度: 经360纬180
    // 苹果地图能显示的最大跨度147左右
    if (latitude > 140 || longitude > 140) {
      return;
    }
    //2. 设置    // 设置范围,带动画
  [self.mapView setRegion:MKCoordinateRegionMake(self.mapView.region.center,MKCoordinateSpanMake(latitude, longitude)) animated:YES];
  });
  
}

#pragma mark - MapView代理方法
/**
 当完成用户位置更新的时候回调用
 userLocation: 显示用户位置的大头针模型(MKUserLocation是系统大头针模型)
*/

-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
   //1. 获取经纬度
  NSLog(@"la: %f, long: %f",userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude);
  //2. 设置标题子标题
  //    userLocation.title = @"北京市";
  //    userLocation.subtitle = @"asasflsdafsa";
 //2.1 创建Geocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2.2 调用反地理编码方法 -->头文件第一个方法
  [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) {
    //2.3 解析数据
    if (placemarks.count ==0 || error) {
      return;
    }
    CLPlacemark *placemark = placemarks.firstObject;
    //locality: 城市
    if (placemark.locality) {
      userLocation.title = placemark.locality;
    } else {
        //administrativeArea: 行政区域,吧行政区域付给大头针模型的title
        userLocation.title = placemark.administrativeArea;
    }
    //name: 详细地址
    userLocation.subtitle = placemark.name;
 
    }];
  
    //设置地图中心坐标点   有BUG   可以试试用Manager 定位后设置中心点
    CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
    self.mapView.centerCoordinate = centerCoordinate;
    //a) 设置缩放
    MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
    //b) 设置区域
    MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
    //显示区域
    self.mapView.region = region;
    self.mapView.region=MKCoordinateRegionMake(CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude), MKCoordinateSpanMake(0.008, 0.008));
  
}

/**
 地图显示区域发生改变时调用
  */
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
  //1. 获取当前显示大小的跨度
  NSLog(@"latitudeDelta: %f,longitudeDelta: %f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
  // 放大地图:将显示跨度缩小一倍即可
  // 放大地图:将显示跨度放大一倍即可
  // 在按钮点击的时候,先获取当前显示跨度大小,然后按照需求放大或缩小跨度,最后再次调用setRegion方法
  // latitudeDelta: 0.046142,longitudeDelta: 0.034943首次运行完毕:
  // latitudeDelta: 0.021251,longitudeDelta: 0.016093
  // latitudeDelta: 0.010625,longitudeDelta: 0.008047

}

#pragma mark 返回用户的位置
-(void)rightItemBtnClick{
  // 设置地图的中心点经纬度 -->没有动画
  //self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
  // 设置地图的中心点经纬度 -->有动画
  //[self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate animated:YES];
  // 设置地图的中心点经纬度并且改变地图的显示跨度
  //1. 中心点坐标.
  CLLocationCoordinate2D centerCoordinate =self.mapView.userLocation.location.coordinate;
  //2. 显示跨度大小 1°约等于111KM
  MKCoordinateSpan span =MKCoordinateSpanMake(0.01,0.01);
  //3. 设置Region属性 -->没有动画
  //self.mapView.region = MKCoordinateRegionMake(centerCoordinate, span);
  // 调用set方法来增加动画
  [self.mapView setRegion:MKCoordinateRegionMake(centerCoordinate, span)animated:YES];
}

-(void)searchItemBtnClick{
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(22.809787,113.154024);
  //创建一个位置信息对象,第一个参数为经纬度,第二个为纬度检索范围,单位为米,第三个为经度检索范围,单位为米
  MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoordinate, 50000, 50000);
  //初始化一个检索请求对象
  MKLocalSearchRequest * req = [[MKLocalSearchRequest alloc]init];
  //设置检索参数
  req.region=region;
  //兴趣点关键字
  req.naturalLanguageQuery=@"hotal";
  //初始化检索
  MKLocalSearch * ser = [[MKLocalSearch alloc]initWithRequest:req];
  //开始检索,结果返回在block中
  [ser startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    //兴趣点节点数组
    NSArray * array = [NSArray arrayWithArray:response.mapItems];
    for (int i=0; i
(经纬度,地址)跳去苹果自带的地图导航

实例代码地址

本代码点击导航栏右边按键的经纬度就把当前位置的经纬度和目标地点的经纬度传递到苹果自带的地图App进行导航 或者 点击导航栏右边按键的地址就把当前位置的地址和目标地点的地址传递到苹果自带的地图App进行导航

#import "NavigationVC.h"
#import 

@interface NavigationVC ()

@end

@implementation NavigationVC

- (void)viewDidLoad {
    [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];
  
  //设置导航栏的文字按键
  UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"地址" style:UIBarButtonItemStylePlain target:self action:@selector(rightItemBtnClick)];
  //设置文字颜色
  [rightItem setTintColor:[UIColor redColor]];
  
  //设置导航栏的文字按键
  UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:@"经纬" style:UIBarButtonItemStylePlain target:self action:@selector(leftItemBtnClick)];
  //设置文字颜色
  [leftItem setTintColor:[UIColor redColor]];
  
  self.navigationItem.rightBarButtonItems = @[rightItem,leftItem];
  
}

//直接输入地址
-(void)rightItemBtnClick{
  //1. 创建CLGeocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2. 调用地理编码方法
  [geocoder geocodeAddressString:@"广东省,佛山市,顺德区,杏坛镇,逢简" completionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) {
    //3. 解析数据
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      return;
    }
    //3.2 获取CLPlacemar对象 -->地理编码
    // 正向会有多个结果,咱们暂时取出一个
    CLPlacemark *pm = placemarks.lastObject;
    //3.3 创建一个MKPlacemark对象
    MKPlacemark *mkpm = [[MKPlacemark alloc]initWithPlacemark:pm];
    //3.4 终点位置
    MKMapItem *destinationItem = [[MKMapItem alloc]initWithPlacemark:mkpm];
    //3.5 当前位置
    MKMapItem *sourceItem = [MKMapItem mapItemForCurrentLocation];
    NSLog(@"name-%@",sourceItem.name);
    //实现导航关键点:在于一个MKMapItem的open方法
    //MKMapItem: 地图上的点
    //需要起点和终点
    //3.6 调用系统地图进行导航
    NSArray *maptems = @[sourceItem, destinationItem];
    // 导航模式. 地图类型.交通状态
    NSDictionary *options =@{MKLaunchOptionsDirectionsModeKey :MKLaunchOptionsDirectionsModeTransit,MKLaunchOptionsMapTypeKey :@(MKMapTypeHybrid)};
    [MKMapItem openMapsWithItems:maptems launchOptions:options];
    }];
  /**
     MKMapTypeStandard = 0,
     MKMapTypeSatellite,
     MKMapTypeHybrid,
    */

}

//直接输入经纬度
-(void)leftItemBtnClick{
  //1. 创建CLGeocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2. 调用地理编码方法
  [geocoder geocodeAddressString:@"广东省,佛山市,顺德区,杏坛镇,逢简" completionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) {
    //3. 解析数据
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      return;
    }
    //3.2 获取CLPlacemar对象 -->地理编码
    // 正向会有多个结果,咱们暂时取出一个
    CLPlacemark *pm = placemarks.lastObject;
    //3.3 创建一个MKPlacemark对象
    MKPlacemark *mkpm = [[MKPlacemark alloc]initWithPlacemark:pm];
    //3.4 终点位置
    MKMapItem *destinationItem = [[MKMapItem alloc]initWithPlacemark:mkpm];
    //3.5 当前位置
    MKMapItem *sourceItem = [MKMapItem mapItemForCurrentLocation];
    //实现导航关键点:在于一个MKMapItem的open方法
    //MKMapItem: 地图上的点
    //需要起点和终点
    //3.6 调用系统地图进行导航
    NSArray *maptems = @[sourceItem, destinationItem];
    // 导航模式. 地图类型.交通状态
    NSDictionary *options =@{MKLaunchOptionsDirectionsModeKey :MKLaunchOptionsDirectionsModeTransit,MKLaunchOptionsMapTypeKey :@(MKMapTypeHybrid)};
    [MKMapItem openMapsWithItems:maptems launchOptions:options];
  }];
  
//  [geocoder reverseGeocodeLocation:userLocation.locationcompletionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) { }];

  
}

@end
路线划线

实例代码地址
下面的代码里面可以通过经纬度画线条也可以通过地址画线条

#import "MapLineDrawingVC.h"
#import 

@interface MapLineDrawingVC ()

@property (nonatomic,strong) CLLocationManager *mgr;
@property (nonatomic,strong) MKMapView *mapView;

@end

@implementation MapLineDrawingVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
  
  //设置导航栏的文字按键
  UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"地址画线" style:UIBarButtonItemStylePlain target:self action:@selector(rightItemBtnClick)];
  //设置文字颜色
  [rightItem setTintColor:[UIColor redColor]];
  
  //设置导航栏的文字按键
  UIBarButtonItem *locationItem = [[UIBarButtonItem alloc] initWithTitle:@"经纬度画线" style:UIBarButtonItemStylePlain target:self action:@selector(locationItemClick)];
  //设置文字颜色
  [locationItem setTintColor:[UIColor redColor]];
  
  self.navigationItem.rightBarButtonItems = @[rightItem,locationItem];
  
  self.mapView = [[MKMapView alloc] init];
  self.mapView.addTo(self.view).makeCons(^{
    make.left.top.right.bottom.equal.view(self.view);
  });
  
  //请求授权 -->想要获取自己位置必须授权
  self.mgr = [CLLocationManager new];
  if ([self.mgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [self.mgr requestWhenInUseAuthorization];
  }
  //设置代理
  self.mapView.delegate =self;
  
  self.mapView.userTrackingMode = MKUserTrackingModeFollow;
  
}

-(void)locationItemClick{
  //1. 创建Geocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2.1 创建位置对象
  CLLocation *location = [[CLLocation alloc] initWithLatitude:22.809787 longitude:113.154024];
  //2.2 调用反地理编码方法
  [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *_Nullable placemarks,NSError *_Nullable error) {
    //3. 解析数据
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      return;
    }
    //3.2 获取CLPlacemar对象 -->地理编码
    // 正向会有多个结果,咱们暂时取出一个
    CLPlacemark *pm = placemarks.lastObject;
    //3.3 创建一个MKPlacemark对象
     MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm];
    //3.4 终点位置
    MKMapItem *destinationItem = [[MKMapItem alloc]initWithPlacemark:mkpm];
    //3.5 当前位置
    MKMapItem *sourceItem = [MKMapItem mapItemForCurrentLocation];
    //3.6 计算路线
    //1. 创建一个方向请求对象 --> 拼接URL地址的参数
     MKDirectionsRequest *request = [MKDirectionsRequest new];
    request.source = sourceItem;
    request.destination = destinationItem;
    //2. 创建方向对象
    MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
    //3. 调用方法计算路线
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
      //3.1 防错处理
      if (response.routes.count == 0 || error) {
        return;
      }
      //3.2 获取路线信息polyline
      for (MKRoute *route in response.routes) {
       // 获取折线 多段线 polyline
        MKPolyline *polyline = route.polyline;
        //3.3 添加地图遮盖物
        //Overlay: 遮盖物
        [self.mapView addOverlay:polyline];
      }
    }];
    
    }];
}

-(void)rightItemBtnClick{
  //1. 创建CLGeocoder对象
  CLGeocoder *geocoder = [CLGeocoder new];
  //2. 调用地理编码方法
  [geocoder geocodeAddressString:@"广东佛山顺德北窖" completionHandler:^(NSArray *_Nullable placemarks, NSError * _Nullable error) {
    //3. 解析数据
    //3.1 防错处理
    if (placemarks.count ==0 || error) {
      return;
    }
    //3.2 获取CLPlacemar对象 -->地理编码
    // 正向会有多个结果,咱们暂时取出一个
    CLPlacemark *pm = placemarks.lastObject;
    //3.3 创建一个MKPlacemark对象
     MKPlacemark *mkpm = [[MKPlacemark alloc] initWithPlacemark:pm];
    //3.4 终点位置
    MKMapItem *destinationItem = [[MKMapItem alloc]initWithPlacemark:mkpm];
    //3.5 当前位置
    MKMapItem *sourceItem = [MKMapItem mapItemForCurrentLocation];
    //3.6 计算路线
    //1. 创建一个方向请求对象 --> 拼接URL地址的参数
     MKDirectionsRequest *request = [MKDirectionsRequest new];
    request.source = sourceItem;
    request.destination = destinationItem;
    //2. 创建方向对象
    MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
    //3. 调用方法计算路线
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
      //3.1 防错处理
      if (response.routes.count == 0 || error) {
        return;
      }
      //3.2 获取路线信息polyline
      for (MKRoute *route in response.routes) {
       // 获取折线 多段线 polyline
        MKPolyline *polyline = route.polyline;
        //3.3 添加地图遮盖物
        //Overlay: 遮盖物
        [self.mapView addOverlay:polyline];
      }
    }];
   }];

}

#pragma mark 还需要设置渲染物对象 --> MapView代理方法
/**
根据遮盖物来完成渲染
*/

//Renderer: 渲染
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay{
  //1. 创建一个渲染物对象 MKPolylineRenderer-->MKOverlayRenderer子类
   MKPolylineRenderer *polyline = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
  //2. 设置线条颜色 --> 默认无色
  polyline.strokeColor = [UIColor colorWithHex:0x1E90FF];
  polyline.fillColor = [UIColor colorWithHex:0x87CEFA];
  polyline.lineWidth = 4.0;
  return polyline;
}

#pragma mark - MapView代理方法
/**
 当完成用户位置更新的时候回调用
 userLocation: 显示用户位置的大头针模型(MKUserLocation是系统大头针模型)
 */

-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
  //设置地图中心坐标点   有BUG   可以试试用Manager 定位后设置中心点
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude,userLocation.location.coordinate.longitude);
  self.mapView.centerCoordinate = centerCoordinate;
  //a) 设置缩放
  MKCoordinateSpan span = MKCoordinateSpanMake(0.1, 0.1);
  //b) 设置区域
  MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
  //显示区域
  self.mapView.region = region;
  self.mapView.region=MKCoordinateRegionMake(CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude), MKCoordinateSpanMake(0.008, 0.008));
  
}

@end
插入标签(系统自带)

OC 原生地图 插入大头针(搜索热点)源码

本例子主要说明:
1.搜索热点
2.插入大头针(系统)

主要实现的代码

-(void)searchView:(SearchView *)view searchValue:(NSString *)value{
  self.searchValue = value;
  
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(self.location.latitude,self.location.longitude);
  //创建一个位置信息对象,第一个参数为经纬度,第二个为纬度检索范围,单位为米,第三个为经度检索范围,单位为米
  MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoordinate, 50000, 50000);
  //初始化一个检索请求对象
  MKLocalSearchRequest * req = [[MKLocalSearchRequest alloc]init];
  //设置检索参数
  req.region=region;
  //兴趣点关键字
  req.naturalLanguageQuery = value;
  //初始化检索
  MKLocalSearch * ser = [[MKLocalSearch alloc]initWithRequest:req];
  //开始检索,结果返回在block中
  [ser startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    //兴趣点节点数组
    NSArray * array = [NSArray arrayWithArray:response.mapItems];
    for (int i=0; i
插入标签(自定义View)

插入标签代码地址

本例子是在上面需求的基础上插入系统的大头针改为自定义的view

第一步:启动之前首先通过遵守代理定位当前的的位置
#pragma mark 定位的代理方法
/**
 当完成位置更新的时候调用
 locations: 位置信息数据
 此方法会频繁调用.非常耗电
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
  //5. 停止定位( 如果不 停止定为就是持续定位)
  [self.locationManager stopUpdatingLocation];
  
  if (locations.count <= 0) { return; }
  self.location = locations.lastObject.coordinate;
  //1. 中心点坐标.
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(locations.lastObject.coordinate.latitude,locations.lastObject.coordinate.longitude);
  //2. 显示跨度大小 1°约等于111KM
  MKCoordinateSpan span =MKCoordinateSpanMake(0.01,0.01);
  //3. 设置Region属性 -->没有动画
  //self.mapView.region = MKCoordinateRegionMake(centerCoordinate, span);
  // 调用set方法来增加动画
  [self.mapView setRegion:MKCoordinateRegionMake(centerCoordinate, span)animated:YES];
  
}
第二步:根据关键字把热点的经纬度保存起来
-(void)searchView:(SearchView *)view searchValue:(NSString *)value{
  self.searchValue = value;
  
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(self.location.latitude,self.location.longitude);
  //创建一个位置信息对象,第一个参数为经纬度,第二个为纬度检索范围,单位为米,第三个为经度检索范围,单位为米
  MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoordinate, 50000, 50000);
  //初始化一个检索请求对象
  MKLocalSearchRequest * req = [[MKLocalSearchRequest alloc]init];
  //设置检索参数
  req.region=region;
  //兴趣点关键字
  req.naturalLanguageQuery = value;
  //初始化检索
  MKLocalSearch * ser = [[MKLocalSearch alloc]initWithRequest:req];
  //开始检索,结果返回在block中
  [ser startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    //兴趣点节点数组
    NSArray * array = [NSArray arrayWithArray:response.mapItems];
    self.arr = array;
    for (int i=0; i
第三步:自定义view实现大头针插进去
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
  for (MKMapItem * item in self.arr) {
    if (item.placemark.coordinate.latitude == annotation.coordinate.latitude && item.placemark.coordinate.longitude == annotation.coordinate.longitude) {
      MapFindProductAnnotationView * view = [[MapFindProductAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"annotation"];      
      view.value = item.name;
      CGFloat width = [item.name sizeWithFont:[UIFont systemFontOfSize:14] maxSize:CGSizeMake(CGFLOAT_MAX, 24)].width + 20;
      view.image = [UIImage createImageWithColor:[Color themeLight] withRect:CGRectMake(0, 0, width, 24)];
      view.delegate = self;
      view.btn.str(item.name);
      return view;
    }
  }
  return nil;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/996639.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)