1 MapKit基础使用
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named MKMapView'
如果storyboard中用到了地图, 必须手动导入框架
#import <MapKit/MapKit.h>
@interface ViewController ()<MKMapViewDelegate>
/**
* 地图
*/
@property (weak, nonatomic) IBOutlet MKMapView *customMapView;
@property (nonatomic, strong) CLLocationManager *mgr;
/**
* 地理编码对象
*/
@property (nonatomic ,strong) CLGeocoder *geocoder;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1.设置地图显示的类型
/*
typedef enum : NSUInteger {
MKMapTypeStandard , 标准(默认)
MKMapTypeSatellite ,卫星
MKMapTypeHybrid 混合(标准 + 卫星)
} MKMapType;
*/
self.customMapView.mapType = MKMapTypeSatellite;
//2.CoreLocation框架定位
// 注意:在iOS8中, 如果想要追踪用户的位置, 必须自己主动请求隐私权限
if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
// 主动请求权限
self.mgr = [[CLLocationManager alloc] init];
[self.mgr requestAlwaysAuthorization];
}
//3. 设置不允许地图旋转
self.customMapView.rotateEnabled = NO;
//4. 成为mapVIew的代理
self.customMapView.delegate = self;
//5. 如果想利用MapKit获取用户的位置, 可以追踪
/*
typedef NS_ENUM(NSInteger, MKUserTrackingMode) {
MKUserTrackingModeNone = 0, 不追踪/不准确的
MKUserTrackingModeFollow, 追踪
MKUserTrackingModeFollowWithHeading, 追踪并且获取用的方向
}
*/
self.customMapView.userTrackingMode = MKUserTrackingModeFollow;
}
#pragma MKMapViewDelegate
/**
* 每次更新到用户的位置就会调用(调用不频繁, 只有位置改变才会调用)
* @param userLocation 大头针模型
*/
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
/*
地图上蓝色的点就称之为大头针
大头针可以拥有标题/子标题/位置信息
大头针上显示什么内容由大头针模型确定(MKUserLocation)
*/
//1.设置大头针内容
// 利用反地理编码获取位置之后设置标题
[self.geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks firstObject];
NSLog(@"获取地理位置成功 name = %@ locality = %@", placemark.name, placemark.locality);
userLocation.title = placemark.name;
userLocation.subtitle = placemark.locality;
}];
//2.设置大头针显示范围
// 移动地图到当前用户所在位置。
// [self.customMapView setCenterCoordinate:userLocation.location.coordinate animated:YES];
//3. 设置地图显示的区域,也会移动地图到当前用户所在位置
// 获取用户的位置
CLLocationCoordinate2D center = userLocation.location.coordinate;
// 指定经纬度的跨度
MKCoordinateSpan span = MKCoordinateSpanMake(0.009310,0.007812);
// 将用户当前的位置作为显示区域的中心点, 并且指定需要显示的跨度范围
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
// 设置显示区域
[self.customMapView setRegion:region animated:YES];
}
//- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
/**
* 地图的区域改变完成时调用。通常用来获取显示范围的经纬度。
* 1度等于110km
*/
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(@"地图的区域改变完成时调用");
// 0.119170 0.100000
// 0.238531 0.200156
// 0.009310 0.007812
NSLog(@"%f %f", self.customMapView.region.span.latitudeDelta, self.customMapView.region.span.longitudeDelta);
}
#pragma mark - 懒加载
- (CLGeocoder *)geocoder
{
if (!_geocoder) {
_geocoder = [[CLGeocoder alloc] init];
}
return _geocoder;
}
2 自定义大头针
**
**要在1,基础使用的前提下自定义
//添加数据到模型中
- (IBAction)addAnno {
// 创建大头针模型
HMAnnotation *anno = [[HMAnnotation alloc] init];
anno.title = @"传智";
anno.subtitle = @"育新小区";
CGFloat latitude = 36.821199 + arc4random_uniform(20);
CGFloat longitude = 116.858776 + arc4random_uniform(20);
anno.coordinate = CLLocationCoordinate2DMake(latitude , longitude);
anno.icon = @"category_1";
// 添加大头针
[self.customMapView addAnnotation:anno];
// 创建大头针模型
HMAnnotation *anno2 = [[HMAnnotation alloc] init];
anno2.title = @"传智2";
anno2.subtitle = @"育新小区2";
CGFloat latitude2 = 36.821199 + arc4random_uniform(20);
CGFloat longitude2 = 116.858776 + arc4random_uniform(20);
anno2.coordinate = CLLocationCoordinate2DMake(latitude2 , longitude2);
anno2.icon = @"category_2";
// 添加大头针
[self.customMapView addAnnotation:anno2];
}
//添加多少次数据到annotation,就会调用多少次这个代理方法
#pragma MKMapViewDelegate
/**
* 每次添加大头针就会调用(地图上有几个大头针就调用几次)
*
* @param mapView 地图
* @param annotation 大头针模型
*
* @return 大头针的view
*/
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// 对用户当前的位置的大头针特殊处理,定位位置大头针不变
// 注意: 如果return nil, 系统会按照自己默认的方式显示
if ([annotation isKindOfClass:[HMAnnotation class]] == NO) {
return nil;
}
static NSString *identifier = @"anno";
/* 1.从缓存池中取
2.如果缓存池中没有, 创建一个新的
1>注意: 默认情况下MKAnnotationView是无法显示的,除非使用图标图片属性,否则想自定义大头针可以使用MKAnnotationView的子类MKPinAnnotationView
2>.注意: 如果是自定义的大头针, 默认情况点击大头针之后是不会显示标题的, 需要我们自己手动设置显示,要设置annoView.canShowCallout = YES;
//强制转换为子类
MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
//两个MKPinAnnotationView的特有属性
annoView.pinColor = MKPinAnnotationColorPurple; //设置大头针的颜色
annoView.animatesDrop = YES; //设置大头针从天而降
*/
MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annoView == nil) {
annoView = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:identifier];
annoView = [[MKAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:identifier];
// 设置大头针标题是否显示
annoView.canShowCallout = YES;
// 设置大头针标题显示的偏移位
annoView.calloutOffset = CGPointMake(0, 0);
// 设置大头针左边的辅助视图
annoView.leftCalloutAccessoryView = [[UISwitch alloc] init];
// 设置大头针右边的辅助视图
annoView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
}
// 设置大头针的图片
// 注意: 如果你是使用的MKPinAnnotationView创建的自定义大头针, 那么设置图片无效, 因为系统内部会做一些操作, 覆盖掉我们自己的设置
HMAnnotation *anno = (HMAnnotation *)annotation;
annoView.image = [UIImage imageNamed:anno.icon];
// 3.给大头针View设置数据
annoView.annotation = annotation;
// 4.返回大头针View
return annoView;
}
//
/************以下方法是封装MKAnnotationView(没有涉及到它的子类MKPinAnnotationView),类似与tableView的cell*************/
#import "HMAnnotationView.h"
#import "HMAnnotation.h" //数据模型
@implementation HMAnnotationView
//初始化
- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
// 初始化
// 设置大头针标题是否显示
self.canShowCallout = YES;
// 设置大头针左边的辅助视图
self.leftCalloutAccessoryView = [[UISwitch alloc] init];
// 设置大头针右边的辅助视图
self.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
}
return self;
}
+ (instancetype)annotationViewWithMap:(MKMapView *)mapView
{
static NSString *identifier = @"anno";
// 1.从缓存池中取
HMAnnotationView *annoView = (HMAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
// 2.如果缓存池中没有, 创建一个新的
if (annoView == nil) {
annoView = [[HMAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:identifier];
}
return annoView;
}
//- (void)setAnnotation:(id<MKAnnotation>)annotation
- (void)setAnnotation:(HMAnnotation *)annotation
{
[super setAnnotation:annotation];
// 处理自己特有的操作
self.image = [UIImage imageNamed:annotation.icon];
}