目录
一. 定位功能
iPhone手机定位(基站定位, WiFi定位, GPS定位: 定位所需时间递增, 精确度递增)
- 导入CoreLocation库
- 创建CLLocationManager对象
- 设置更新位置的周期(距离)
- 设置定位的精度
- 开始定位
- iOS8中要在Info.plist添加一组键值对, 并执行
- (void)requestWhenInUseAuthorization
方法- 遵守协议
<CLLocationManagerDelegate>
后可以获取更新位置
二. 系统地图
- 导入MapKit库
- 创建地图对象, 设置地图类型, 地图区域(region包含中心点和半径), 显示视图
- 定位当前位置(除了CLLocationManager对象外, 要设置显示位置
_mapView.showsUserLocation = YES
)- 在CLLocationManager的代理方法中, 设置将地图位置设置地图的中心点
[_mapView setCenterCoordinate:loc.coordinate animated:YES]
三. 系统地图的大头针
- 设置地图对象
- 设置大头针(一般通过手势点击来添加大头针MKPointAnnotation: 需要设置其经纬度, 酌情设置大小标题和左右视图)
- 显示大头针: 设置地图对象的代理, 遵守MKMapViewDelegate协议
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
- 想要通过点击大头针的Callout视图中的UIControl对象调用方法的话, 需要遵守
MKMapViewDelegate
协议实现代理方法- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
- 注意点: 如果想创建静态图片作为大头针图片的话,可以创建MKAnnotationView实例;如果想使用apple自带的大头针则创建MKPinAnnotationView
If the annotation can be represented by a static image, create an instance of the MKAnnotationView class and assign the image to its image property; see “Using the Standard Annotation Views.”
If you want to use a standard pin annotation, create an instance of the MKPinAnnotationView class; see “Using the Standard Annotation Views.”
四. 自定义大头针
- 自定义大头针类MyAnnotation(需要遵守MKAnnotation协议, 需要自己设标题, 副标题, 经纬度; 不需要设置左右两个视图)
- 显示mapView, 在mapView上添加长按手势以添加自定义Annotation, 在代理方法中- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation中显示Annotation(可以设置Annotation的图片, 添加左右CalloutAccessoryView)
- 之后就可以通过一些设置来弹出视图, 传参......
五. 地址解析和反地址解析
六. 高德地图
- 前期准备: 按照官网教程
- 显示地图, 搜索地点, 地址解码和反解码的示例代码
一. 定位功能
1. 导入CoreLocation的头文件, 设置定位管理对象为成员变量
{
// 定位管理对象
CLLocationManager *_manager;
}
2. 设置定位管理对象
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// iOS8之前做到5步就可以
// 1. 创建定位管理对象
_manager = [[CLLocationManager alloc] init];
// 2. 表示手机移动50米才更新定位的位置
_manager.distanceFilter = 50;
// 3. 表示定位的精度
_manager.distanceFilter = kCLLocationAccuracyBest;
// 4. 设置代理
_manager.delegate = self;
// 5. 开始定位
[_manager startUpdatingLocation];
// 6. 获取手机的方向, 去对应代理方法中获取
// [_manager startUpdatingHeading];
// iOS8需要设置Info.plist文件里面的值
// NSLocationWhenInUseUsageDescription == YES
// NSLocationAlwaysUsageDescription == YES
if ([_manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_manager requestWhenInUseAuthorization];
}
if ([_manager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_manager requestAlwaysAuthorization];
}
}
3. 在-Supporting Files文件夹下的Info.plist添加一个boolean类型的键值对NSLocationWhenInUseUsageDescription
, 并设为YES, 如下图所示
4. 遵守协议<CLLocationManagerDelegate>
, 实现代理方法
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"error:%@", error);
}
// iOS6之前
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
}
// 定位成功后
// iOS6之后
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if (locations.count > 0) {
// 获取位置信息
CLLocation *loc = [locations lastObject];
CLLocationCoordinate2D coor = loc.coordinate;
// NSLog(@"%@", locations);
NSLog(@"latitude: %lf, longitude: %lf", coor.latitude, coor.longitude);
/*
计算速度
速度 = 位移 / 时间
*/
// if (_lastLoc) {
//
// // 计算位置 将一个位置设为成员变量
// CLLocationDistance dis = [loc distanceFromLocation:_lastLoc];
// // 计算时间
// NSTimeInterval time = [loc.timestamp timeIntervalSinceDate:_lastLoc.timestamp];
//
// CGFloat speed = dis / time;
//
// _lastLoc = loc;
// }
}
// 关闭定位
[_manager stopUpdatingLocation];
// 关闭获取定位方向
// [_manager stopUpdatingHeading];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// 相对地理北极的方向
// newHeading.trueHeading;
// 相对磁北极的方向
// newHeading.magneticHeading;
}
二. 系统地图
1. 导入MapKit/MapKit.h
, 创建地图视图对象成员变量
@interface ViewController () <MKMapViewDelegate>
{
// 地图对象
MKMapView *_mapView;
}
2. 新建地图对象, 设置属性
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 1. 创建地图对象
_mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 20, 320, 568 - 20)];
// 2. 地图类型
/*
MKMapTypeStandard,
MKMapTypeSatellite,
MKMapTypeHybrid
*/
_mapView.mapType = MKMapTypeHybrid;
// 3. 设置代理
_mapView.delegate = self;
// 4. 显示地图
[self.view addSubview:_mapView];
// 5. 设置地图的位置
// 中心点
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(31, 121);
// center = {32, 122}; 另一种创建结构体的方式
// span 0-1
MKCoordinateSpan span = MKCoordinateSpanMake(0.2, 0.2);
// 区域
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
_mapView.region = region;
}
3. 定位到所在位置: 创建定位管理对象, 遵守CLLocationManagerDelegate协议, 实现协议方法
- (void)viewDidLoad {
[super viewDidLoad];
// 开启定位功能
_manager = [[CLLocationManager alloc] init];
// 每隔多少距离使用位置更新数据
_manager.distanceFilter = 50;
// 定位的精度
_manager.desiredAccuracy = kCLLocationAccuracyBest;
// 代理属性
_manager.delegate = self;
[_manager startUpdatingLocation];
// iOS8
// NSLocationWhenInUseUsageDescription == YES;
if ([_manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_manager requestWhenInUseAuthorization];
}
// 地图对象
…………………………………………………………………………………………
// 6. 显示定位位置
_mapView.showsUserLocation = YES;
}
#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"error:%@", error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if (locations.count > 0) {
CLLocation *loc = locations[0];
// 将地图位置设置地图的中心点
[_mapView setCenterCoordinate:loc.coordinate animated:YES];
}
}
三. 系统地图的大头针
1. 设置好地图和大头针(大头针暂时不会显示)
#import "ViewController.h"
#import <MapKit/MapKit.h>
@interface ViewController ()
{
MKMapView *_mapView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 创建一个视图
_mapView = [[MKMapView alloc] initWithFrame:CGRectMake(30, 100, 300, 500)];
_mapView.mapType = MKMapTypeStandard;
[self.view addSubview: _mapView];
// 设置区域
// 1. 中心点
/*
typedef struct {
CLLocationDegrees latitude;
CLLocationDegrees longitude;
} CLLocationCoordinate2D;
*/
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(39, 116);
// 2. 半径
/*
typedef struct {
CLLocationDegrees latitudeDelta;
CLLocationDegrees longitudeDelta;
} MKCoordinateSpan;
*/
MKCoordinateSpan span = MKCoordinateSpanMake(0.2, 0.2);
// 3. 区域
/*
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;
*/
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
_mapView.region = region;
// 添加一个长按手势, 点击后, 在这个位置加一个大头针
// 在实际项目中, 需要去请求一个接口, 返回的数据对象中会包含每个对象的经纬度信息, 然后根据经纬度去显示一个大头针
[_mapView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]];
}
- (void)longPressAction:(UILongPressGestureRecognizer *)gesture
{
// 获取经纬度信息
CGPoint point = [gesture locationInView:_mapView];
// 坐标转换为经纬度
CLLocationCoordinate2D coor = [_mapView convertPoint:point toCoordinateFromView:_mapView];
// 添加大头针
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
// 设置经纬度
annotation.coordinate = coor;
// 标题
annotation.title = @"大标题";
// 小标题
annotation.subtitle = @"小标题";
[_mapView addAnnotation:annotation];
}
2. 显示大头针, 以及大头针的标题: 设置地图对象的代理, 遵守MKMapViewDelegate
协议
- (void)viewDidLoad {
…………………………………………………………………………………………
_mapView.delegate = self;
}
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// 重用ID
static NSString *annotationId = @"annotationId";
// 从重用队列中获取
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationId];
if (nil == annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationId];
}
// 设置属性
annotationView.canShowCallout = YES;
return annotationView;
}
3. 点击大头针, 在弹出的视图左右显示视图(如果是UIControl的子类的话, 点击调用的方法要实现代理方法 - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
里面)
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
…………………………………………………………………………………………
// 在左边显示图片
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
imageView.image = [UIImage imageNamed:@"blue.png"];
annotationView.leftCalloutAccessoryView = imageView;
// 在右边显示一个按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView = btn;
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(@"%s", __func__);
}
四. 自定义大头针
1. 自定义大头针类MyAnnotation
(需要遵守MKAnnotation
协议, 需要自己设标题, 副标题, 经纬度; 不需要设置左右两个视图)
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
/*
自定义大头针类型
title: 标题
subtitle: 小标题
*/
@interface MyAnnotation : NSObject <MKAnnotation>
- (instancetype)initWithCoor:(CLLocationCoordinate2D)coor title:(NSString *)title subtitle:(NSString *)subTitle;
@end
#import "MyAnnotation.h"
@implementation MyAnnotation
{
// 经纬度
CLLocationCoordinate2D _myCoor;
// 标题
NSString *_myTitle;
// 副标题
NSString *_mySubtitle;
}
- (instancetype)initWithCoor:(CLLocationCoordinate2D)coor title:(NSString *)title subtitle:(NSString *)subtitle
{
if (self = [super init]) {
_myCoor = coor;
_myTitle = title;
_mySubtitle = subtitle;
}
return self;
}
#pragma mark - MKAnnotation
- (NSString *)title
{
return _myTitle;
}
- (NSString *)subtitle
{
return _mySubtitle;
}
- (CLLocationCoordinate2D)coordinate
{
return _myCoor;
}
@end
2. 显示mapView, 在mapView上添加长按手势以添加自定义Annotation, 在代理方法中- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
中显示Annotation(可以设置Annotation的图片, 添加左右CalloutAccessoryView)
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *annoId = @"annoId";
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:annoId];
if (nil == annoView) {
annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annoId];
}
annoView.image = [UIImage imageNamed:@"mark"];
annoView.canShowCallout = YES;
// 右边添加按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annoView.rightCalloutAccessoryView = btn;
return annoView;
}
3. 之后就可以通过一些设置来弹出视图, 传参......
五. 系统地图的地址解析和反地址解析
地址解析: 将地址解析为经纬度
反地址解析: 将经纬度解析为地址
#import "ViewController.h"
#import "MyUtility.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()
{
// 地址输入框
UITextField *_addressTextField;
// 经纬度
UITextField *_latitudeTextField;
UITextField *_longitudeTextField;
// 解析对象
CLGeocoder *_geocoder;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createView];
// 初始化解析对象
_geocoder = [[CLGeocoder alloc] init];
}
- (void)createView
{
// 地址
_addressTextField = [MyUtility createTextField:CGRectMake(30, 100, 200, 40) placeHolder:@"请输入地址"];
[self.view addSubview:_addressTextField];
UIButton *parserBtn = [MyUtility createButtonWithFrame:CGRectMake(240, 100, 60, 40) title:@"解析" backgroundImageName:nil target:self action:@selector(geoAction)];
[self.view addSubview:parserBtn];
// 经纬度
_latitudeTextField = [MyUtility createTextField:CGRectMake(30, 200, 90, 40) placeHolder:@"纬度"];
[self.view addSubview:_latitudeTextField];
_longitudeTextField = [MyUtility createTextField:CGRectMake(140, 200, 90, 40) placeHolder:@"经度"];
[self.view addSubview:_longitudeTextField];
UIButton *reverseBtn = [MyUtility createButtonWithFrame:CGRectMake(240, 200, 60, 40) title:@"泛解析" backgroundImageName:nil target:self action:@selector(reverseGeoAction)];
[self.view addSubview:reverseBtn];
}
// 地址解析
- (void)geoAction
{
if (_addressTextField.text.length > 0) {
// 解析
[_geocoder geocodeAddressString:_addressTextField.text completionHandler:^(NSArray *placemarks, NSError *error) {
// 解析结束时调用该block
NSLog(@"%@", placemarks);
for (CLPlacemark *placemark in placemarks) {
// placemark 是符合条件的地址信息
NSLog(@"ISOcountryCode:%@", placemark.ISOcountryCode);
NSLog(@"administrativeArea:%@", placemark.administrativeArea);
NSLog(@"addressDictionary:%@", placemark.addressDictionary);
NSLog(@"latitude:%lf\nlongitude:%lf", placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);
}
}];
}
}
// 反地址解析
- (void)reverseGeoAction
{
if (_longitudeTextField.text.length > 0 && _latitudeTextField.text.length > 0) {
// 反解析
CLLocation *loc = [[CLLocation alloc] initWithLatitude:_latitudeTextField.text.floatValue longitude:_longitudeTextField.text.floatValue];
[_geocoder reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error) {
for (CLPlacemark *placemark in placemarks) {
NSLog(@"%@", placemark.addressDictionary);
NSLog(@"%@", [placemark.addressDictionary objectForKey:@"City"]);
}
}];
}
}
六. 高德地图
1. 前期准备: 按照官网教程
2. 显示地图, 搜索地点, 地址解码和反解码的示例代码
#import "MyUtility.h"
#import "ViewController.h"
#import <MAMapKit/MAMapKit.h>
#import <AMapSearchKit/AMapSearchAPI.h>
#define kAMapKey (@"97ae63c2d20ed3b23767312e2d2ab609")
@interface ViewController () <MAMapViewDelegate, AMapSearchDelegate>
{
// 地图
MAMapView *_mapView;
// 搜索对象(搜索, 解析都需要该对象)
AMapSearchAPI *_searchAPI;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 设置key值
[MAMapServices sharedServices].apiKey = kAMapKey;
_searchAPI =[[AMapSearchAPI alloc] initWithSearchKey:kAMapKey Delegate:self];
// 创建高德地图
_mapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, 100, 320, 568 - 100)];
_mapView.mapType = MAMapTypeStandard;
_mapView.delegate = self;
[self.view addSubview:_mapView];
// 添加三个按钮
[self createThreeButton];
}
- (void)createThreeButton
{
UIButton *addSearchButton = [MyUtility createButtonWithFrame:CGRectMake(30, 30, 100, 40) title:@"搜地址" backgroundImageName:nil target:self action:@selector(searchPalce)];
UIButton *geocoderButton = [MyUtility createButtonWithFrame:CGRectMake(140, 30, 100, 40) title:@"解析" backgroundImageName:nil target:self action:@selector(geocoderAction)];
UIButton *reverseGeocoderButton = [MyUtility createButtonWithFrame:CGRectMake(250, 30, 60, 40) title:@"反解析" backgroundImageName:nil target:self action:@selector(reverseGeocoderAction)];
[self.view addSubview:addSearchButton];
[self.view addSubview:geocoderButton];
[self.view addSubview:reverseGeocoderButton];
}
- (void)searchPalce
{
AMapPlaceSearchRequest *request = [[AMapPlaceSearchRequest alloc] init];
// 设置搜索的类型
request.searchType = AMapSearchType_PlaceKeyword;
// 城市的数组
request.city = @[@"北京"];
// 搜索关键字
request.keywords = @"江南";
// 搜索
[_searchAPI AMapPlaceSearch:request];
}
// 地址解析
- (void)geocoderAction
{
AMapGeocodeSearchRequest *request = [[AMapGeocodeSearchRequest alloc] init];
// 类型
request.searchType = AMapSearchType_Geocode;
// 城市
request.city = @[@"beijing"];
// 地址
request.address = @"天安门";
// 搜索
[_searchAPI AMapGeocodeSearch:request];
}
- (void)reverseGeocoderAction
{
AMapReGeocodeSearchRequest *request = [[AMapReGeocodeSearchRequest alloc] init];
// 类型
request.searchType = AMapSearchType_ReGeocode;
// 设置经纬度
AMapGeoPoint *point = [[AMapGeoPoint alloc] init];
point.latitude = 31;
point.longitude = 121;
request.location = point;
// 是否返回扩展信息
request.requireExtension = YES;
[_searchAPI AMapReGoecodeSearch:request];
}
- (void)obtainBundleIdentifier
{
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
NSLog(@"%@", bundleIdentifier);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - AMapSearchAPI代理
// 地址搜索
- (void)onPlaceSearchDone:(AMapPlaceSearchRequest *)request response:(AMapPlaceSearchResponse *)response
{
NSMutableArray *array = [NSMutableArray array];
for (AMapPOI *poi in response.pois) {
// poi.location.latitude
// 创建一个大头针对象
MAPointAnnotation *anno = [[MAPointAnnotation alloc] init];
anno.coordinate = CLLocationCoordinate2DMake(poi.location.latitude, poi.location.longitude);
anno.title = poi.name;
anno.subtitle = poi.city;
[array addObject:anno];
}
// 移除之前的大头针
[_mapView removeAnnotations:_mapView.annotations];
// 添加到地图上
[_mapView addAnnotations:array];
}
// 地址解析
- (void)onGeocodeSearchDone:(AMapGeocodeSearchRequest *)request response:(AMapGeocodeSearchResponse *)response
{
NSMutableArray *array = [NSMutableArray array];
for (AMapGeocode *geoCode in response.geocodes) {
// 创建大头针
MAPointAnnotation *anno = [[MAPointAnnotation alloc] init];
anno.coordinate = CLLocationCoordinate2DMake(geoCode.location.latitude, geoCode.location.longitude);
anno.title = geoCode.formattedAddress;
[array addObject:anno];
}
// 移除之前的大头针
[_mapView removeAnnotations:_mapView.annotations];
// 添加到地图上
[_mapView addAnnotations:array];
}
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
NSLog(@"%@", response.regeocode.formattedAddress);
AMapPlaceSearchRequest *request1 = [[AMapPlaceSearchRequest alloc] init];
// 设置搜索的类型
request1.searchType = AMapSearchType_PlaceKeyword;
// 城市的数组
request1.city = @[@"上海"];
// 搜索关键字
request1.keywords = response.regeocode.formattedAddress;
// 搜索
[_searchAPI AMapPlaceSearch:request1];
}
#pragma mark - MAMapView代理
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation
{
static NSString *annoId = @"annoId";
MAAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:annoId];
if (nil == annoView) {
annoView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annoId];
}
annoView.canShowCallout = YES;
return annoView;
}
@end