热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS学习笔记20地图(二)MapKit框架

一、地图开发介绍从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的。在iOS中进行地图开发主要有三种方式:利用MapKit框架进行地图

一、地图开发介绍

从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的。

在iOS中进行地图开发主要有三种方式:
  • 利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制
  • 调用苹果官方自带的地图应用,主要用于一些简单的地图应用,无法精确控制
  • 使用第三方地图开发SDK库

用得最多的还是MapKit,所以这节就只讲MapKit的使用。

二、MapKit核心类

MapKit的核心类为地图展示控件MKMapView,以下是常用的属性、对象方法以及代理方法。

1. 属性:

/* 用户位置跟踪 */
@property (nonatomic) BOOL showsUserLocation;/*<是否在地图上标注用户位置 */
@property (nonatomic, readonly) MKUserLocation *userLocation;/*<用户位置 */
@property (nonatomic) MKUserTrackingMode userTrackingMode;/*<用户跟踪类型 */
typedef NS_ENUM(NSInteger, MKUserTrackingMode) {
	MKUserTrackingModeNOne= 0, /*<不跟踪 */
	MKUserTrackingModeFollow, /*<跟踪 */
	MKUserTrackingModeFollowWithHeading,  /*<导航跟踪 */
};
/* 设置地图配置项 */
@property (nonatomic) MKMapType mapType;/*<地图类型 */
@property (nonatomic, readonly) NSArray *annotations;/*<大头针数组 */
typedef NS_ENUM(NSUInteger, MKMapType) {
    MKMapTypeStandard = 0,/*<标准地图 */
    MKMapTypeSatellite,/*<卫星地图 */
    MKMapTypeHybrid,/*<混合模式(标准+卫星) */
    MKMapTypeSatelliteFlyover,/*<3D立体卫星(iOS9.0) */
    MKMapTypeHybridFlyover,/*<3D立体混合(iOS9.0) */
}
/* 设置地图控制项 */
@property (nonatomic) BOOL zoomEnabled;/*<是否可以缩放 */
@property (nonatomic) BOOL scrollEnabled;/*<是否可以滚动 */
@property (nonatomic) BOOL rotateEnabled;/*<是否可以旋转 */
@property (nonatomic) BOOL pitchEnabled;/*<是否显示3D视角 */
/* 设置地图显示项 */
@property (nonatomic) BOOL showsBuildings;/*<是否显示建筑物,只影响标准地图 */
@property (nonatomic) BOOL showsTraffic;/*<是否显示交通,iOS9 */
@property (nonatomic) BOOL showsCompass;/*<是否显示指南针,iOS9 */
@property (nonatomic) BOOL showsScale;/*<是否显示比例尺,iOS9 */

所谓大头针就是地图上显示的这个标注:
iOS学习笔记20-地图(二)MapKit框架

2. 对象方法:

/* 添加大头针 */
- (void)addAnnotation:(id )annotation;
- (void)addAnnotations:(NSArray> *)annotations;
/* 删除大头针 */
- (void)removeAnnotation:(id )annotation;
- (void)removeAnnotations:(NSArray> *)annotations;
/* 选中大头针与取消选中大头针 */
- (void)selectAnnotation:(id )annotation 
                animated:(BOOL)animated;
- (void)deselectAnnotation:(id )annotation 
                  animated:(BOOL)animated;
/* 获取大头针视图 */
- (MKAnnotationView *)viewForAnnotation:(id )annotation;
/* 从缓冲池中取出大头针视图控件 */
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
/* 设置显示区域以及地图中心坐标 */
- (void)setRegion:(MKCoordinateRegion)region 
         animated:(BOOL)animated;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate 
                   animated:(BOOL)animated;
/* 经纬度坐标转UIKit坐标,UIKit坐标转经纬度坐标 */
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate 
               toPointToView:(UIView *)view;
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point 
                  toCoordinateFromView:(UIView *)view;

3. 常用代理方法MKMapViewDelegate

/* 地图加载完成会调用 */
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView;
/* 地图加载失败会调用 */
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error;
/* 用户位置发生改变会调用 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation;
/* 显示区域改变会调用 */
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
/* 点击选中大头针时会调用 */
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
/* 取消选中大头针时会调用 */
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view;
/* 显示地图上的大头针,功能类似于UITableView的tableView:cellForRowAtIndexPath:方法 */
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation;

三、MapKit使用

1. 首先添加头文件:

#import 

2. 初始化地图展示控件MKMapView

- (void)initMapView{
    CGFloat x = 0;
    CGFloat y = 20;
    CGFloat width = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    //创建MKMapView,设置控件视图大小
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(x, y, width, height)];
    //设置地图类型
    mapView.mapType = MKMapTypeStandard;
    //设置代理
    mapView.delegate = self;
    [self.view addSubview:mapView];
    self.mapView = mapView;
}

3. 用户位置跟踪

在iOS8之前,实现这个功能只需要:
  1. 设置用户跟踪模式
  2. mapView:DidUpdateUserLocation:代理方法中设置地图中心和显示范围
在iOS8之后,用法稍有不同:
  1. 必须按照前面的定位章节的,获取前台或者前后台的定位服务授权,下面是链接:
    iOS学习笔记19-地图(一)定位CoreLocation
  2. 不需要进行中心点的指定,默认会将当前位置设置为中心点并自动显示区域范围
  3. 只有定位到当前位置后mapView:DidUpdateUserLocation:代理方法才会调用
- (void)viewDidLoad {
    [super viewDidLoad];
    //获取定位服务授权
    [self requestUserLocationAuthor];
    //初始化MKMapView
    [self initMapView];
}
- (void)requestUserLocationAuthor{
    //如果没有获得定位授权,获取定位授权请求
    self.locatiOnM= [[CLLocationManager alloc] init];
    if ([CLLocationManager locationServicesEnabled]) {
        if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
            [self.locationM requestWhenInUseAuthorization];
        }
    }
}
- (void)initMapView{
    CGFloat x = 0;
    CGFloat y = 20;
    CGFloat width = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    //创建MKMapView对象
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(x, y, width, height)];
    //设置地图类型
    mapView.mapType = MKMapTypeStandard;
    //设置用户跟踪模式
    mapView.userTrackingMode = MKUserTrackingModeFollow;
    mapView.delegate = self;
    [self.view addSubview:mapView];
    self.mapView = mapView;
}
#pragma mark - MKMapViewDelegate
/* 更新用户位置会调用 */
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
    CLLocation *location = userLocation.location;
    CLLocationCoordinate2D coordinate = location.coordinate;
    NSLog(@"经度:%f,纬度:%f",coordinate.latitude,coordinate.longitude);
}

iOS学习笔记20-地图(二)MapKit框架

4. 添加大头针

MapKit没有自带的大头针,只有大头针协议MKAnnotation,我们需要自定义大头针:

  1. 创建一个继承NSObject的类
  2. 实现MKAnnotation协议
  3. 必须创建一个属性,用于存储大头针位置
@property (nonatomic) CLLocationCoordinate2D coordinate;
下面就是我简单创建的LTAnnotation类:
#import 
#import 

@interface LTAnnotation : NSObject 
/* 必须创建的属性 */
@property (nonatomic) CLLocationCoordinate2D coordinate;
/* 可选的属性 */
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
/* 自定义的属性 */
@property (nonatomic, strong) UIImage *icon;
@end

@implementation LTAnnotation
@end
下面是实际的使用:
- (void)viewDidLoad {
    [super viewDidLoad];
    //请求定位授权
    [self requestUserLocationAuthor];
    //初始化MKMapView
    [self initMapView];
    //添加大头针
    [self addAnnotationsToMapView];
}
- (void)addAnnotationsToMapView{
    CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(22.54, 114.02);
    //创建大头针
    LTAnnotation *annotation = [[LTAnnotation alloc] init];
    annotation.title = @"执着";
    annotation.subtitle = @"执着哥开的店";
    annotation.coordinate = location1;
    annotation.icon = [UIImage imageNamed:@"red"];
    //添加大头针
    [self.mapView addAnnotation:annotation1];
}

iOS学习笔记20-地图(二)MapKit框架

iOS学习笔记20-地图(二)MapKit框架

5. 自定义大头针视图

上面的大头针样子是不是很丑,那是MKMapView的默认样式大头针视图MKAnnotationView,我们先来了解下它的常用属性:

@property (nonatomic, strong) id annotation;/*<大头针数据 */
@property (nonatomic, strong) UIImage *image;/*<大头针的图标 */
@property (nonatomic, readonly) NSString *reuseIdentifier;/*<大头针的唯一标示 */
@property (nonatomic) CGPoint calloutOffset;/*<弹出视图的偏移 */
@property (nonatomic) BOOL selected;/*<是否选中 */
@property (nonatomic) BOOL canShowCallout;/*<是否能点击弹出视图 */
@property (nonatomic, strong) UIView *leftCalloutAccessoryView;/*<弹出视图左边的视图 */
@property (nonatomic, strong) UIView *rightCalloutAccessoryView;/*<弹出视图右边的视图 */
下面是通过设置MKAnnotationView的属性,自定义大头针视图:
/* 每当大头针显示在可视界面上时,就会调用该方法,用户位置的蓝色点也是个大头针,也会调用 */
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
{
    if ([annotation isKindOfClass:[LTAnnotation class]]) {
        LTAnnotation *annotatiOnLT= (LTAnnotation *)annotation;
        //类似于UITableViewCell的重用机制,大头针视图也有重用机制
        static NSString *key = @"AnnotationIdentifier";
        MKAnnotationView *view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:key];
        if (!view) {
            view = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                reuseIdentifier:key];
        }
        //设置大头针数据
        view.annotation = annotation;
        //自定义大头针默认是NO,表示不能弹出视图,这里让大头针可以点击弹出视图
        view.canShowCallout = YES;
        //设置大头针图标
        view.image = annotationLT.icon;
        //设置弹出视图的左边视图
        UIImage *leftImage = [UIImage imageNamed:@"cafeIcon"];
        UIImageView *leftView = [[UIImageView alloc] initWithImage: leftImage];
        leftView.bounds = CGRectMake(0, 0, 50, 50);
        view.leftCalloutAccessoryView = leftView;
        //设置弹出视图的右边视图
        UIImage *rightImage = [UIImage imageNamed:@"cafeRight"];
        UIImageView *rightView = [[UIImageView alloc] initWithImage: rightImage];
        rightView.bounds = CGRectMake(0, 0, 50, 50);
        view.rightCalloutAccessoryView = rightView;
        return view;
    }
    //返回nil,表示显示默认样式
    return nil;
}

iOS学习笔记20-地图(二)MapKit框架

四、扩展--自定义大头针弹出详情视图

如果你去关注下一些地图应用,会发现他们的弹出视图和我们的完全不一样,那是怎么实现的呢?

实际上那不是弹出视图,那是个大头针,只是这个大头针做得和弹出视图很像而已。

实现思路:
  1. 当点击普通的大头针时,移除地图上其他的详情大头针,添加当前大头针的详情大头针
  2. 当普通大头针取消选中时,移除地图上所有的详情大头针
  3. mapView:viewForAnnotation:方法中设置普通大头针视图和详情大头针视图
下面是实现的部分代码【实现效果比较随便,见谅】:
#pragma mark - 地图控件代理方法
/* 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象 */
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
    //由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图
    if ([annotation isKindOfClass:[LTAnnotation class]]) {
        static NSString *key1 = @"AnnotationKey1";
        MKAnnotationView *annotatiOnView= [_mapView dequeueReusableAnnotationViewWithIdentifier:key1];
        //如果缓存池中不存在则新建
        if (!annotationView) {
            annotatiOnView= [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                          reuseIdentifier:key1];
            annotationView.canShowCallout = NO;//不允许弹出视图,但可以被选中
        }
        //重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)
        annotationView.annotation = annotation;
        annotationView.image = ((LTAnnotation *)annotation).icon;//设置大头针视图的图片
        return annotationView;
    }else if([annotation isKindOfClass:[LTCalloutAnnotation class]]){
        static NSString *key2 = @"AnnotationCallOutKey2";
        MKAnnotationView *calloutView = [_mapView dequeueReusableAnnotationViewWithIdentifier:key2];
        //如果缓存池中不存在则新建
        if (!calloutView) {
            calloutView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                       reuseIdentifier:key2];
            calloutView.canShowCallout = NO;//不允许弹出视图,但可以被选中
        }
        //对于作为弹出详情视图的自定义大头针视图无弹出交互功能,在其中可以***添加其他视图
        calloutView.annotation = annotation;
        //设置详情大头针的偏移位置
        calloutView.centerOffset = CGPointMake(-50, -80);
        [self calloutAddSubView:calloutView];
        return calloutView;
    } else {
        return nil;
    }
}

上面我的LTCalloutAnnotation和LTAnnotation实际上是只是类名不同而已,属性都一样。

#pragma mark 添加弹出视图的子控件,这里我就很随便了,你可以搞得好看点
- (void)calloutAddSubView:(MKAnnotationView *)calloutView
{
    //添加背景
    UIView *background = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 60)];
    background.backgroundColor = [UIColor whiteColor];
    background.layer.borderWidth = 5;
    background.layer.borderColor = [UIColor blueColor].CGColor;
    [calloutView addSubview:background];
    //添加图片
    UIImage *image = [UIImage imageNamed:@"cafeRight"];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
    imageView.frame = CGRectMake(5, 5, 50, 50);
    [calloutView addSubview:imageView];
    //添加一个红色方块
    UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(60, 5, 35, 40)];
    subview.backgroundColor = [UIColor redColor];
    [calloutView addSubview:subview];
}

#pragma mark 选中大头针时触发
//点击一般的大头针KCAnnotation时添加一个大头针作为所点大头针的弹出详情视图
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
    if ([view.annotation isKindOfClass:[LTAnnotation class]]) {
        LTAnnotation *annotation = view.annotation;
        //点击一个大头针时移除其他弹出详情视图
        [self removeCalloutAnnotation];
        //添加详情大头针
        LTCalloutAnnotation *callout = [[LTCalloutAnnotation alloc] init];
        callout.icon = annotation.icon;
        callout.title = annotation.title;
        callout.subtitle = annotation.subtitle;
        callout.coordinate = annotation.coordinate;
        [self.mapView addAnnotation:callout];
    }
}
#pragma mark 取消选中时触发
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
    [self removeCalloutAnnotation];
}
#pragma mark 移除所用详情大头针
-(void)removeCalloutAnnotation{
    [self.mapView.annotations enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop){
        if ([obj isKindOfClass:[LTCalloutAnnotation class]]) {
            [_mapView removeAnnotation:obj];
        }
    }];
}

iOS学习笔记20-地图(二)MapKit框架

这个自定义弹出详情视图,我做的比较简陋,我主要是为了好说明具体是怎么实现的,你可以把弹出界面做的好看点,顺便把一些大头针视图进行下封装,那一切就很完美了,O(∩_∩)O哈!这种实现是很低效的,每次都需要遍历所有的大头针,从中找到详情大头针,需要优化的地方很多,可以自己去想着优化。

如果有什么意见请在下方评论区写出来,求关注,求打赏,O(∩_∩)O哈!

推荐阅读
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 本文详细介绍了在MyBatis框架中如何通过#和$两种方式来传递SQL查询参数。使用#方式可以提高执行效率,而使用$则有助于在复杂SQL语句中更好地查看日志。此外,文章还探讨了不同场景下的参数传递方法,包括实体对象、基本数据类型以及混合参数的使用。 ... [详细]
  • 本文介绍了如何使用Java编程语言实现凯撒密码的加密与解密功能。凯撒密码是一种替换式密码,通过将字母表中的每个字母向前或向后移动固定数量的位置来实现加密。 ... [详细]
  • 题面:P3178[HAOI2015]树上操作好像其他人都嫌这道题太容易了懒得讲,好吧那我讲。题解:第一个操作和第二个操作本质上是一样的&# ... [详细]
  • Java中List的forEach方法与字符串拼接的兼容性问题
    本文深入探讨了在Java中使用List的forEach方法时遇到的字符串拼接问题,提供了有效的解决方案及背后的原理分析,旨在帮助开发者更好地理解和解决此类问题。 ... [详细]
  • 本文详细介绍了如何使用Linux下的mysqlshow命令来查询MySQL数据库的相关信息,包括数据库、表以及字段的详情。通过本文的学习,读者可以掌握mysqlshow命令的基本语法及其常用选项。 ... [详细]
  • selenium通过JS语法操作页面元素
    做过web测试的小伙伴们都知道,web元素现在很多是JS写的,那么既然是JS写的,可以通过JS语言去操作页面,来帮助我们操作一些selenium不能覆盖的功能。问题来了我们能否通过 ... [详细]
  • 本文深入探讨了MySQL中的高级特性,包括索引机制、锁的使用及管理、以及如何利用慢查询日志优化性能。适合有一定MySQL基础的读者进一步提升技能。 ... [详细]
  • iOS如何实现手势
    这篇文章主要为大家展示了“iOS如何实现手势”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“iOS ... [详细]
  • 在使用mybatis进行mapper.xml测试的时候发生必须为元素类型“mapper”声明属性“namespace”的错误项目目录结构UserMapper和UserMappe ... [详细]
  • egg实现登录鉴权(七):权限管理
    权限管理包含三部分:访问页面的权限,操作功能的权限和获取数据权限。页面权限:登录用户所属角色的可访问页面的权限功能权限:登录用户所属角色的可访问页面的操作权限数据权限:登录用户所属 ... [详细]
  • C/C++ 应用程序的安装与卸载解决方案
    本文介绍了如何使用Inno Setup来创建C/C++应用程序的安装程序,包括自动检测并安装所需的运行库,确保应用能够顺利安装和卸载。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • 多路查找树:B树与B+树详解
    本文详细介绍了B树及其变种B+树的基本概念、特性以及应用场景。B树作为一种平衡的多路查找树,在数据库和文件系统中有着广泛的应用。文章不仅解释了B树的定义,还深入探讨了B树的结构特点及操作方法。 ... [详细]
author-avatar
yellow start
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有