ios cllocationnManager的方向在真机上怎么是

求助:IOS CLLocationManager获取的坐标 如何转换成为百度坐标_百度地图api吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:4,102贴子:
求助:IOS CLLocationManager获取的坐标 如何转换成为百度坐标收藏
有朋友知道吗!!!分享一下!!!感谢!!!
API页面上提供的坐标转换不知道可不可以
BMKMapPoint points = BMKMappointForCoordinate(coor);shi yi shi
CLLocationManager获取的坐标是由google坐标系得到的坐标,转化为百度坐标系百度有在官方API未公开实际存在的接口做转换。
/** *坐标转换函数,从原始GPS坐标,mapbar坐标转换成百度坐标 * coorWgs84 待转换的原始GPS坐标,或者mapbar的坐标 * 返回的NSDictionry中包含“x”,“y”字段,各自对应经过base64加密之后的x,y坐标 */UIKIT_EXTERN NSDictionary* BMKBaiduCoorForWgs84(CLLocationCoordinate2D coorWgs84);/** *坐标转换函数,从google坐标,51地图坐标,mapabc坐标转换为百度坐标(51地图坐标需要显出10000) * coorGcj 待转换的google坐标,51地图坐标,mapabc坐标 * 返回的NSDictionry中包含“x”,“y”字段,各自对应经过base64加密之后的x,y坐标 */UIKIT_EXTERN NSDictionary* BMKBaiduCoorForGcj(CLLocationCoordinate2D coorGcj);/** *base64加密后的坐标字典解密函数 * dictionary 带解密的NSDictionry,该NSDictionry中应包含“x”,“y”字段,各自对应经过base64加密之后的x,y坐标 * 解密之后的坐标*/UIKIT_EXTERN CLLocationCoordinate2D BMKCoorDictionaryDecode(NSDictionary* dictionary);根据你说的需求应该选用第3个方法BMKCoorDictionaryDecode(BMKBaiduCoorForWgs84(Location)); Location为你通过CLLocationManager获取的坐标。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或cllocationmanager---1
有了iPhone,意味着我们不会再迷路了。有了iPhone内建的全球定位系统(Global Positioning
System,GPS)硬件,以及一些创新的位置和地图软件,iPhone不仅随时知道你位于何处,而且还能显示给你看。
iPhone使用所谓的辅助GPS技术来搞清楚你位于何处。有了内建的GPS接收器,iPhone可以利用通信塔台和Wi-Fi热点之间的三角信息,来增加它发送给应用程序的位置数据的准确性。
在本章中,我们首先介绍Core Location,这是让我们快速且轻松地找到当前位置的框架。然后,我们将介绍Map
Kit框架,它使我们能够把流行的Google
Maps引擎所支持的地图添加到自己的应用中。我们还将看看如何轻松地执行反向地理编码来获取一个位置的地址,最后,我们把所有这些概念组合到一个地图应用程序中,它能够再现本地Maps应用程序的很多功能。
8.1&& Core Location
Location是用来为iPhone应用添加位置识别功能的框架,其设计看上去很简单。CLLocationManager及其委托方法提供了一种机制,通过该机制来获取位置信息并发送给应用程序。直接创建一个实例,可选择性地设置一些精确度选项,然后调用startUpdatingLocation方法。
CLLocation事件通过CLLocationManager实例的委托方法产生。CLLocation对象不仅封装了地理信息,而且还有速度、高度、方向和精确度等信息。
让应用程序能够识别位置的方法如下:
1)创建一个基于视图的应用程序,将其保存为CoreLocationExample(如图8-1所示)。
2)在Groups &
Files面板中,展开Targets部分,鼠标右键点击你的应用程序目标,并且选择Get
Info。确保选中General标签,点击Linked Libraries列表底部的Add
(+),并且添加CoreLocation框架(如图8-2所示)。
3)打开CoreLocationExampleViewController.h文件,导入CoreLocation框架,添加CL-LocationManagerDelegate协议声明,并创建一个实例变量来保存位置管理器(见程序清单8-1)。
创建基于视图的应用程序&&&&&&&&&&&&&
图8-2&& 向项目中添加CoreLocation框架
4)切换到CoreLocationExampleView
Controller.m文件,取消对viewDidLoad方法的注释,并添加如下代码:
lm = [[CLLocationManager alloc]
lm.delegate =
[lm startUpdatingLocation];
创建CLLocationManager实例,设置委托为视图控制器(self),然后告诉位置管理器开始发送位置事件。程序清单8-2给出了完整的应用程序代码。
程序清单8-1&& Core
Location应用程序的头文件
程序清单8-2&& 一个基本的Core
Location应用程序
8.1.1&& 处理位置更新
不管你是否相信,就是这样,应用程序现在可以识别位置了。然而,我们还是没有任何办法来处理位置管理器给我们的信息。要做到这点,我们必须实现所需的委托方法(别忘了,我们还要把CLLocationManagerDelgate协议添加到CLLocationManager.h中)。
CLLocationManager只有两个委托方法。第一个是locationManager:didUpdateTo
Location:fromLocation:,当位置管理器更新一个新的位置的时候调用。之前的位置和新的位置都会传递,除非这是第一个位置事件,在那种情况下fromLocation:将会是nil。
第二个委托方法locationManager:didFail
WithError:,用于处理位置管理器试图获取一个位置值的时候所发生的任何错误。在这种情况下,可以通过一个stopUpdatingLocation调用来停止位置管理器,以节省电池电量。
程序清单8-3给出了更新后的Core LocationExampleViewController.m文件。
输出发送到控制台(如图8-3所示),给出了纬度/经度坐标、结果的精确度(在这个例子中精确到100米)、我们的速度、我们的路径或方向、位置事件何时发生的一个时间戳。
程序清单8-3&& 更新后的Core
Location应用程序显示到控制台
图8-3&& Debugger控制台显示位置信息
·注意,要保持电池电量,只要有一个位置或发生错误,就在位置管理器上调用stopUpdatingLocation。
·当第一次启动位置管理器的时候(通过startUpdatingLocation),它通常会快速连续地产生许多位置更新。这通常只是校准位置或者缓存位置,往往不够精确并且可以忽略。我们将在本章稍后介绍一种技术来处理这种情况
8.1.2&& 在模拟器之外测试
从事过航海导航的读者可能注意到,当你自己运行前面的例子的时候,纬度和经度不能和你当前的位置对应(除非你现在Apple公司工作)。当基于Core
Location的代码在iPhone模拟器中运行的时候,它总是报告一个位置:“1 Infinite Loop,
Cupertino”(Apple公司总部所在地)。
显然路径和速度这样的元素在模拟器中不可能测试。此外,如果你拿着自己的iPhone走动并测试应用程序,显然不能在计算机屏幕上看到控制台的输出。
从现在开始,我们假设本章中的例子都是在一个实际的设备上而不是模拟器中运行。我们将向iPhone的主视图添加一个UITextView,并且编写一些代码在设备上而不是控制台上显示输出。
我们可以很容易地挂系UILabel控件或者其他更吸引人的UI元素,这是一种方便的快捷方式,让我们花费最少的力气就很容易地显示输出信息。
在iPhone屏幕上添加位置数据的记录:
1)在CoreLocationExampleViewController.h中,创建一个实例变量来保存你的视图(见程序清单8-4):
UITextView *logV
2)切换到CoreLocationExampleView
Controller.m,并且创建logToScreen:方法,我们将用此方法把文本显示到iPhone屏幕上:
CGPoint pt = logView.contentO
我们首先设置一个变量来保存UIView的当前内容在其滚动视图中的位置:
logView.text = [NSString
→stringWithFormat:@"%@\n%@",
→logView.text,output];
接下来,附加新的文本,如果新文本比单个屏幕大的话,确保视图可以相应地滚动:
[logView setContentOffset:pt
→animated:NO];
[logView scrollRangeToVisible:
→NSMakeRange([logView.text length],
程序清单8-4&& 更新后的头文件
图8-4&& 输出信息显示在iPhone上
3)更新viewDidLoad方法以便创建并添加新的视图:
logView = [[UITextView alloc]
→initWithFrame:[self.view bounds]];
logView.editable = NO;
logView.userInteractionEnabled =
[self.view addSubview:logView];
4)最后,为了确保操作和NSLog()尽可能地接近,在该文件的顶部定义DCLog宏:
#define DCLog(format, ...)
→[self logToScreen:[NSString
→stringWithFormat:format,
→## __VA_ARGS__]];
现在,我们可以用一个DCLog()调用来替代对NSLog()的调用。输出信息将显示在iPhone的屏幕上(如图8-4所示)。
8.1.3&& 增加精确度
到目前为止,你可能已经注意到所接受的位置信息并不是很精确。这是因为位置管理器初次启动的时候常常返回缓存的或校准的“最佳猜测”值,而且精度会随着时间的增加而提高。
我们可以做一些事情来过滤掉这些不想要的位置事件,并且得到一个更加精确的结果。
我们到目前为止只使用了CLLocation事件的description属性,但是,还应该能够使用其他的几个属性:
·altitude—根据我们在海平面之上还是之下,它可能是一个正值或负值。
·coordinate—一个CLLocationCoordinate类型,包含了纬度和经度信息。
·course, speed—iPhone移动的方向和速度(以米为单位)。
·horizontalAccuracy , verticalAccuracy—坐标和海拔值的精确度
·course以度来度量,北方是0,东方是90,南方是180,西方是270。你可能注意到了,在第一个示例中,course和speed值都是-1.0。由于只有单个的位置,意味着这些值都没有计算。
·horizontalAccuracy和verticalAccuracy的负值通常表示位置事件被忽略了。
8.1.4&& 添加超时
我们还考虑到节省iPhone电池的电量,设置超时,如果在一个合理的时间内没有接收到一个有效的位置,就关闭位置管理器。
为位置管理器添加超时:
1)在CoreLocationExampleViewController.h中,添加一个新的实例变量来保存超时:
2)切换到CoreLocationExampleView
Controller.m,并且向viewDidLoad方法中添加如下新的代码:
lm.desiredAccuracy =
→kCLLocationAccuracyB
lm.distanceFilter =
→kCLDistanceFilterN
这告诉位置管理器,它应该有多么精确,以及用户必须移动多远(以米为单位)后才会产生一个新的位置事件。
然后,我们把定时器设置为1分钟后过时:
timer = [NSTimer scheduledTimer
→WithTimeInterval:60 target:self
→selector:@selector(locationManager
→DidTimeout:userInfo:) userInfo:nil
→repeats:false];
desiredAccuracy代码告诉位置管理器在产生位置事件的时候,它应该努力达到什么样的精度。这个属性可能的值范围从“best”到3千米。然而,这还是值得注意的,尽管位置管理器将试图实现定义的精确度,但这并不能确保。
在这个例子中,我们对desiredAccuracy和distanceFilter都使用最精确的设置。使用这些设置可能会花费较长的时间来返回一个位置,由此会对iPhone的电池寿命有更多的影响,记住这一点很重要。
3)更新位置管理器委托,用于检查位置事件的时间:
NSTimeInterval eventAge =
→[newLocation.timestamp
→timeIntervalSinceNow];
if (abs(eventAge) & 5.0)
我们只对过去5秒钟内发生的事件感兴趣。这将会过滤掉任何缓存的位置数据。如果一个事件足够新,那么我们接下来检查精确度:
if ([newLocation horizontalAccuracy]
→& 0.0f &&
[newLocation
→horizontalAccuracy] &= 100.0f)
这将会只获取那些精确到你的实际位置的100米以内的事件(也确保忽略了负值这样的无效值)。
最后,停止位置管理器和定时器,并且输出结果。
4)还有两件事情要做。首先,需要处理无法找到一个位置的情况:
(void)locationManagerDidTimeout:
→(NSTimer *)aTimer userInfo:(id)
→userInfo
这需要直接停止位置管理器,并且在屏幕上显示一个错误。最后,如果发生错误的话,确保停止定时器,可通过把如下代码加入到locationManager:didFailWithError:委托方法来做到:
[timer invalidate];
程序清单8-5&& 完整的Core
Location代码
图8-5显示了一次成功位置搜索的结果。尝试在你的iPhone上运行这些代码,当位置事件发生的时候,你将会看到它们(如果你在家中的话,可能需要增加超时值),而且精确度会随着时间而增加。尝试修改desiredAccuracy和distanceFilter的值,看看它们如何影响到改变或删除缓存位置检查的结果。
·由于位置管理器是逐渐增加精确度的,并且在一个位置上“校准为零”,这实际上可能是第一个结果,尽管报告为不精确的位置,但实际上是正确的位置。
·快速地显示潜在的不精确的信息与让用户为更精确的结果等待更长时间,这两者之间总是有一种平衡。前面示例中的代码只是一种方法。另一种思路可能是减少想要的精度级别,并且采用统计地址事件的策略,等达到一定数目的时候接受一个作为有效的地址。可以根据应用程序的需求来确定选取哪种方法。
图8-5&& 位置搜索的结果
8.1.5&& 访问指南针
如果iPhone包含一个指南针,我们可以用与获取位置更新同样的方式来获取方向信息。位置管理器把方向更新生成为CLHeading对象,其中包含了表示方向值的属性,该方向值对应于磁场和正北方。这些属性都以度来表示,0表示北方,180表示南方。
检查iPhone是否支持方向更新,我们可以查看位置管理器的headingAvailable属性。开始和停止监听方向事件,我们分别调用startUpdatingHeading和stopUpdatingHeading方法。就像位置更新一样,方向更新也通过委托方法来管理:
·locationManager:didUpdateHeading:—当接收到一个和之前方向不同的新方向(且比headingFilter属性中指定的值大)的时候调用。
·locationManagerShouldDisplayHeading
Calibration:manager—如果iPhone需要校准,调用该方法。通常当一个新iPhone的指南针还没有使用过的时候,会发生这种情况。返回YES将显示指南针校准面板。我们可以通过调用dismissHeadingCalibrationDisplay来关闭该面板,或者可以通过向这个方法返回NO来阻止该面板显示。
到目前为止的例子中,我们主要集中于在停止位置管理器之前尽可能精确地获取单个位置。你可能想要有一个真正的应用程序,能够随着你的走动或开车,连续地更新位置、显示路径、速度和方向信息。我们将在本章8.3节“综合应用”中看到这样的例子。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。iOS8-CLLocationManager定位
在iOS8中的API
&&&requestWhenInUseAuthorization
&&&Discussion:
&&When +authorizationStatus ==
kCLAuthorizationStatusNotDetermined,
&&calling this method will
trigger a prompt to request "when-in-use"
&&authorization from the
user.& If possible, perform this call in
&&to direct user request for a
location-based service so that the reason
&&for the prompt will be
clear.& Any authorization change as a result
&&the prompt will be reflected
via the usual delegate callback:
&&-locationManager:didChangeAuthorizationStatus:.
&&If received, "when-in-use"
authorization grants access to the user's
&&location via
-startUpdatingLocation/-startRangingBeaconsInRegion
foreground.& If updates have been started when
going to the
&&background, then a status bar
banner will be displayed to maintain
&&visibility to the user, and
updates will continue until stopped
&&normally, or the app is killed
by the user.
&&"When-in-use" authorization
does NOT enable monitoring API on regions,
&&significant location changes,
or visits, and -startUpdatingLocation will
&&not succeed if invoked from the
background.
&&When +authorizationStatus !=
kCLAuthorizationStatusNotDetermined, (ie
&&generally after the first call)
this method will do nothing.
the NSLocationWhenInUseUsageDescription key is not specified in your
&&Info.plist, this method will do
nothing, as your app will be assumed not
&&to support WhenInUse
authorization.
- (void)requestWhenInUseAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA,
__IPHONE_8_0);
&&&requestAlwaysAuthorization
&&&Discussion:
&&When +authorizationStatus ==
kCLAuthorizationStatusNotDetermined,
&&calling this method will
trigger a prompt to request "always"
&&authorization from the
user.& If possible, perform this call in
&&to direct user request for a
location-based service so that the reason
&&for the prompt will be
clear.& Any authorization change as a result
&&the prompt will be reflected
via the usual delegate callback:
&&-locationManager:didChangeAuthorizationStatus:.
&&If received, "always"
authorization grants access to the user's
&&location via any
CLLocationManager API, and grants access to
&&launch-capable monitoring API
such as geofencing/region monitoring,
&&significante location visits,
etc.& Even if killed by the user,
&&events triggered by monitored
regions or visit patterns will cause a
&&relaunch.
&&"Always" authorization presents
a significant risk to user privacy, and
&&as such requesting it is
discouraged unless background launch behavior
&&is genuinely
required.& Do not call +requestAlwaysAuthorization
&&you think users will thank you
for doing so.
&&When +authorizationStatus !=
kCLAuthorizationStatusNotDetermined, (ie
&&generally after the first call)
this method will do nothing.
&&If the NSLocationAlwaysUsageDescription key is not specified in your
&&Info.plist, this method will do
nothing, as your app will be assumed not
&&to support Always
authorization.
- (void)requestAlwaysAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA,
__IPHONE_8_0);
iOS8 中 CLLocationManager
进行定位的时候,需要显示的调用以上两个API。并且需要在Info.plist文件中添加对应的key(这里要吐槽一下,因为xcode为Info.plist提供的下拉选项中根本没有这两个对应键)
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Posts - 69,
Articles - 0,
Comments - 858
CODING 完美世界...
08:52 by KenshinCui, ... 阅读,
概览 现在很多社交、电商、团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用和导航应用所特有的。的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式。例如你到了一个陌生的地方想要查找附近的酒店、超市等就可以打开软件搜索周边;类似的,还有很多团购软件可以根据你所在的位置自动为你推荐某些商品。总之,目前地图和定位功能已经大量引入到应用开发中。今天就和大家一起看一下iOS如何进行地图和定位开发。
定位 要实现地图、导航功能,往往需要先熟悉定位功能,在iOS中通过Core Location框架进行定位操作。Core Location自身可以单独使用,和地图开发框架MapKit完全是独立的,但是往往地图开发要配合定位框架使用。在Core Location中主要包含了定位、地理编码(包括反编码)功能。 定位功能 定位是一个很常用的功能,如一些地图软件打开之后如果用户允许软件定位的话,那么打开软件后就会自动锁定到当前位置,如果用户手机移动那么当前位置也会跟随着变化。要实现这个功能需要使用Core Loaction中CLLocationManager类,首先看一下这个类的一些主要方法和属性:
+ (BOOL)locationServicesE 是否启用定位服务,通常如果用户没有启用定位服务可以提示用户打开定位服务
+ (CLAuthorizationStatus)authorizationS 定位服务授权状态,返回枚举类型:kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务
desiredAccuracy 定位精度,枚举类型: kCLLocationAccuracyBest:最精确定位CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米误差范围kCLLocationAccuracyHundredMeters:百米误差范围kCLLocationAccuracyKilometer:千米误差范围kCLLocationAccuracyThreeKilometers:三千米误差范围
distanceFilter 位置信息更新最小距离,只有移动大于这个距离才更新位置信息,默认为kCLDistanceFilterNone:不进行距离限制
startUpdatingLocation 开始定位追踪,开始定位后将按照用户设置的更新频率执行-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)方法反馈定位信息
stopUpdatingLocation 停止定位追踪
startUpdatingHeading 开始导航方向追踪
stopUpdatingHeading 停止导航方向追踪
startMonitoringForRegion: 开始对某个区域进行定位追踪,开始对某个区域进行定位后。如果用户进入或者走出某个区域会调用- (void)locationManager:(CLLocationManager *)manager&&& didEnterRegion:(CLRegion *)region和- (void)locationManager:(CLLocationManager *)manager&&& didExitRegion:(CLRegion *)region代理方法反馈相关信息
stopMonitoringForRegion: 停止对某个区域进行定位追踪
requestWhenInUseAuthorization 请求获得应用使用时的定位服务授权,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription
requestAlwaysAuthorization 请求获得应用一直使用定位服务授权,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *) 位置发生改变后执行(第一次定位到某个位置之后也会执行)
- (void)locationManager:(CLLocationManager *)manager&&&&&& didUpdateHeading:(CLHeading *)newH 导航方向发生变化后执行
& - (void)locationManager:(CLLocationManager *)manager&&& didEnterRegion:(CLRegion *)region 进入某个区域之后执行
- (void)locationManager:(CLLocationManager *)manager&&& didExitRegion:(CLRegion *)region 走出某个区域之后执行 iOS 8 还提供了更加人性化的定位服务选项。App 的定位服务不再仅仅是关闭或打开,现在,定位服务的启用提供了三个选项,「永不」「使用应用程序期间」和「始终」。同时,考虑到能耗问题,如果一款 App 要求始终能在后台开启定位服务,iOS 8 不仅会在首次打开 App 时主动向你询问,还会在日常使用中弹窗提醒你该 App 一直在后台使用定位服务,并询问你是否继续允许。在iOS7及以前的版本,如果在应用程序中使用定位服务只要在程序中调用startUpdatingLocation方法应用就会询问用户是否允许此应用是否允许使用定位服务,同时在提示过程中可以通过在info.plist中配置通过配置Privacy - Location Usage Description告诉用户使用的目的,同时这个配置是可选的。但是在iOS8中配置配置项发生了变化,可以通过配置NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。同时,在应用程序中需要根据配置对requestAlwaysAuthorization或locationServicesEnabled方法进行请求。由于本人机器已经更新到最新的iOS8.1下面的内容主要针对iOS8,使用iOS7的朋友需要稍作调整。 //
KCMainViewController.m
CoreLocation
Created by Kenshin Cui on 14-03-27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
@interface KCMainViewController ()&CLLocationManagerDelegate&{
CLLocationManager *_locationM
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
//定位管理器
_locationManager=[[CLLocationManager alloc]init];
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"定位服务当前可能尚未打开,请设置打开!");
//如果没有授权则请求用户授权
if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
[_locationManager requestWhenInUseAuthorization];
}else if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse){
//设置代理
_locationManager.delegate=
//设置定位精度
_locationManager.desiredAccuracy=kCLLocationAccuracyB
//定位频率,每隔多少米定位一次
CLLocationDistance distance=10.0;//十米定位一次
_locationManager.distanceFilter=
//启动跟踪定位
[_locationManager startUpdatingLocation];
#pragma mark - CoreLocation 代理
#pragma mark 跟踪定位代理方法,每次位置发生变化即会执行(只要定位到相应位置)
//可以通过模拟器设置一个虚拟位置,否则在模拟器中无法调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *location=[locations firstObject];//取出第一个位置
CLLocationCoordinate2D coordinate=location.//位置坐标
NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);
//如果不需要实时定位,使用完即使关闭定位服务
[_locationManager stopUpdatingLocation];
1.定位频率和定位精度并不应当越精确越好,需要视实际情况而定,因为越精确越耗性能,也就越费电。
2.定位成功后会根据设置情况频繁调用-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations方法,这个方法返回一组地理位置对象数组,每个元素一个CLLocation代表地理位置信息(包含经度、纬度、海报、行走速度等信息),之所以返回数组是因为有些时候一个位置点可能包含多个位置。
3.使用完定位服务后如果不需要实时监控应该立即关闭定位服务以节省资源。
4.除了提供定位功能,CLLocationManager还可以调用startMonitoringForRegion:方法对指定区域进行监控。
除了提供位置跟踪功能之外,在定位服务中还包含CLGeocoder类用于处理地理编码和逆地理编码(又叫反地理编码)功能。
地理编码:根据给定的位置(通常是地名)确定地理坐标(经、纬度)。
逆地理编码:可以根据地理坐标(经、纬度)确定位置信息(街道、门牌等)。
CLGeocoder最主要的两个方法就是- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionH和- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionH,分别用于地理编码和逆地理编码。下面简单演示一下://
KCMainViewController.m
CoreLocation
Created by Kenshin Cui on 14-03-27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
@interface KCMainViewController ()&CLLocationManagerDelegate&{
CLGeocoder *_
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
_geocoder=[[CLGeocoder alloc]init];
[self getCoordinateByAddress:@"北京"];
[self getAddressByLatitude:39.54 longitude:116.28];
#pragma mark 根据地名确定地理坐标
-(void)getCoordinateByAddress:(NSString *)address{
//地理编码
[_geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
//取得第一个地标,地标中存储了详细的地址信息,注意:一个地名可能搜索出多个地址
CLPlacemark *placemark=[placemarks firstObject];
CLLocation *location=placemark.//位置
CLRegion *region=placemark.//区域
NSDictionary *addressDic= placemark.addressD//详细地址信息字典,包含以下部分信息
NSString *name=placemark.//地名
NSString *thoroughfare=placemark.//街道
NSString *subThoroughfare=placemark.subT //街道相关信息,例如门牌等
NSString *locality=placemark. // 城市
NSString *subLocality=placemark.subL // 城市相关信息,例如标志性建筑
NSString *administrativeArea=placemark.administrativeA // 州
NSString *subAdministrativeArea=placemark.subAdministrativeA //其他行政区域信息
NSString *postalCode=placemark.postalC //邮编
NSString *ISOcountryCode=placemark.ISOcountryC //国家编码
NSString *country=placemark. //国家
NSString *inlandWater=placemark.inlandW //水源、湖泊
NSString *ocean=placemark. // 海洋
NSArray *areasOfInterest=placemark.areasOfI //关联的或利益相关的地标
NSLog(@"位置:%@,区域:%@,详细信息:%@",location,region,addressDic);
#pragma mark 根据坐标取得地名
-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{
//反地理编码
CLLocation *location=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
[_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark=[placemarks firstObject];
NSLog(@"详细信息:%@",placemark.addressDictionary);
iOS从6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的。这样一来,如果在iOS6.0之前进行地图开发的话使用方法会有所不同,基于目前的情况其实使用iOS6.0之前版本的系统基本已经寥寥无几了,所有在接下来的内容中不会再针对iOS5及之前版本的地图开发进行介绍。
在iOS中进行地图开发主要有两种方式,一种是直接利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制;另一种方式是直接调用苹果官方自带的地图应用,主要用于一些简单的地图应用(例如:进行导航覆盖物填充等),无法进行精确的控制。当然,本节重点内容还是前者,后面的内容也会稍加提示。用MapKit之前需要简单了解一下MapKit中地图展示控件MKMapView的的一些常用属性和方法,具体如下表:
userTrackingMode
跟踪类型,是一个枚举:MKUserTrackingModeNone :不进行用户位置跟踪;MKUserTrackingModeFollow :跟踪用户位置;MKUserTrackingModeFollowWithHeading :跟踪用户位置并且跟踪用户前进方向;
地图类型,是一个枚举:MKMapTypeStandard :标准地图,一般情况下使用此地图即可满足;MKMapTypeSatellite :卫星地图;MKMapTypeHybrid :混合地图,加载最慢比较消耗资源;
userLocation
用户位置,只读属性
annotations
当前地图中的所有大头针,只读属性
- (void)addAnnotation:(id &MKAnnotation&)
添加大头针,对应的有添加大头针数组
- (void)removeAnnotation:(id &MKAnnotation&)
删除大头针,对应的有删除大头针数组
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)
设置地图显示区域,用于控制当前屏幕显示地图范围
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)
设置地图中心点位置
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)
将地理坐标(经纬度)转化为数学坐标(UIKit坐标)
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)
将数学坐标转换为地理坐标
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)
从缓存池中取出大头针,类似于UITableView中取出UITableViewCell,为了进行性能优化而设计
- (void)selectAnnotation:(id &MKAnnotation&)annotation animated:(BOOL)
选中指定的大头针
- (void)deselectAnnotation:(id &MKAnnotation&)annotation animated:(BOOL)
取消选中指定的大头针
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userL
用户位置发生改变时触发(第一次定位到用户位置也会触发该方法)
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userL
显示区域发生改变后触发
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapV
地图加载完成后触发
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &MKAnnotation&)
显示大头针时触发,返回大头针视图,通常自定义大头针可以通过此方法进行
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
点击选中某个大头针时触发
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
取消选中大头针时触发
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id &MKOverlay&)overlay
渲染地图覆盖物时触发
用户位置跟踪
在很多带有地图的应用中默认打开地图都会显示用户当前位置,同时将当前位置标记出来放到屏幕中点方便用户对周围情况进行查看。如果在iOS6或者iOS7中实现这个功能只需要添加地图控件、设置用户跟踪模式、在-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation代理方法中设置地图中心区域及显示范围。但是在iOS8中用法稍有不同:
1.由于在地图中进行用户位置跟踪需要使用定位功能,而定位功能在iOS8中设计发生了变化,因此必须按照前面定位章节中提到的内容进行配置和请求。
2.iOS8中不需要进行中心点的指定,默认会将当前位置设置中心点并自动设置显示区域范围。
了解以上两点,要进行用户位置跟踪其实就相当简单了,值得一提的是-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation这个代理方法。这个方法只有在定位(利用前面章节中的定位内容)到当前位置之后就会调用,以后每当用户位置发生改变就会触发,调用频率相当频繁。
在iOS开发中经常会标记某个位置,需要使用地图标注,也就是大家俗称的“大头针”。只要一个NSObject类实现MKAnnotation协议就可以作为一个大头针,通常会重写协议中coordinate(标记位置)、title(标题)、subtitle(子标题)三个属性,然后在程序中创建大头针对象并调用addAnnotation:方法添加大头针即可(之所以iOS没有定义一个基类实现这个协议供开发者使用,多数原因应该是MKAnnotation是一个模型对象,对于多数应用模型会稍有不同,例如后面的内容中会给大头针模型对象添加其他属性)。
KCAnnotation.h//
KCAnnotation.h
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import &MapKit/MapKit.h&
@interface KCAnnotation : NSObject&MKAnnotation&
@property (nonatomic) CLLocationCoordinate2D
@property (nonatomic, copy) NSString *
@property (nonatomic, copy) NSString *
KCMainViewController.m//
KCMainViewController.m
MapKit Annotation
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
-122.406417
39.92 116.39
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
#import "KCAnnotation.h"
@interface KCMainViewController ()&MKMapViewDelegate&{
CLLocationManager *_locationM
MKMapView *_mapV
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initGUI];
#pragma mark 添加地图控件
-(void)initGUI{
CGRect rect=[UIScreen mainScreen].
_mapView=[[MKMapView alloc]initWithFrame:rect];
[self.view addSubview:_mapView];
//设置代理
_mapView.delegate=
//请求定位服务
_locationManager=[[CLLocationManager alloc]init];
if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
[_locationManager requestWhenInUseAuthorization];
//用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)
_mapView.userTrackingMode=MKUserTrackingModeF
//设置地图类型
_mapView.mapType=MKMapTypeS
//添加大头针
[self addAnnotation];
#pragma mark 添加大头针
-(void)addAnnotation{
CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
KCAnnotation *annotation1=[[KCAnnotation alloc]init];
annotation1.title=@"CMJ Studio";
annotation1.subtitle=@"Kenshin Cui's Studios";
annotation1.coordinate=location1;
[_mapView addAnnotation:annotation1];
CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
KCAnnotation *annotation2=[[KCAnnotation alloc]init];
annotation2.title=@"Kenshin&Kaoru";
annotation2.subtitle=@"Kenshin Cui's Home";
annotation2.coordinate=location2;
[_mapView addAnnotation:annotation2];
#pragma mark - 地图控件代理方法
#pragma mark 更新用户位置,只要用户改变则调用此方法(包括第一次定位到用户位置)
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
NSLog(@"%@",userLocation);
//设置地图显示范围(如果不进行区域设置会自动显示区域范围并指定当前用户位置为地图中心点)
MKCoordinateSpan span=MKCoordinateSpanMake(0.01, 0.01);
MKCoordinateRegion region=MKCoordinateRegionMake(userLocation.location.coordinate, span);
[_mapView setRegion:region animated:true];
运行效果:
设置大头针视图
在一些应用中系统默认的大头针样式可能无法满足实际的需求,此时就需要修改大头针视图默认样式。根据前面MapKit的代理方法不难发现- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &MKAnnotation&)方法可以返回一个大头针视图,只要实现这个方法并在这个方法中定义一个大头针视图MKAnnotationView对象并设置相关属性就可以改变默认大头针的样式。MKAnnotationView常用属性:
annotation
大头针模型信息,包括标题、子标题、地理位置。
大头针图片
canShowCallout
点击大头针是否显示标题、子标题内容等,注意如果在- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &MKAnnotation&)方法中重新定义大头针默认情况是无法交互的需要设置为true。
calloutOffset
点击大头针时弹出详情信息视图的偏移量
是否被选中状态
leftCalloutAccessoryView
弹出详情左侧视图
rightCalloutAccessoryView
弹出详情右侧视图
需要注意:
a.这个代理方法的调用时机:每当有大头针显示到系统可视界面中时就会调用此方法返回一个大头针视图放到界面中,同时当前系统位置标注(也就是地图中蓝色的位置点)也是一个大头针,也会调用此方法,因此处理大头针视图时需要区别对待。
b.类似于UITableView的代理方法,此方法调用频繁,开发过程中需要重复利用MapKit的缓存池将大头针视图缓存起来重复利用。
c.自定义大头针默认情况下不允许交互,如果交互需要设置canShowCallout=true
d.如果代理方法返回nil则会使用默认大头针视图,需要根据情况设置。
下面以一个示例进行大头针视图设置,这里设置了大头针的图片、弹出视图、偏移量等信息。
KCAnnotation.h//
KCAnnotation.h
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import &MapKit/MapKit.h&
@interface KCAnnotation : NSObject&MKAnnotation&
@property (nonatomic) CLLocationCoordinate2D
@property (nonatomic, copy) NSString *
@property (nonatomic, copy) NSString *
#pragma mark 自定义一个图片属性在创建大头针视图时使用
@property (nonatomic,strong) UIImage *
KCMainViewController.m//
KCMainViewController.m
MapKit Annotation
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
-122.406417
39.92 116.39
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
#import "KCAnnotation.h"
@interface KCMainViewController ()&MKMapViewDelegate&{
CLLocationManager *_locationM
MKMapView *_mapV
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initGUI];
#pragma mark 添加地图控件
-(void)initGUI{
CGRect rect=[UIScreen mainScreen].
_mapView=[[MKMapView alloc]initWithFrame:rect];
[self.view addSubview:_mapView];
//设置代理
_mapView.delegate=
//请求定位服务
_locationManager=[[CLLocationManager alloc]init];
if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
[_locationManager requestWhenInUseAuthorization];
//用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)
_mapView.userTrackingMode=MKUserTrackingModeF
//设置地图类型
_mapView.mapType=MKMapTypeS
//添加大头针
[self addAnnotation];
#pragma mark 添加大头针
-(void)addAnnotation{
CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
KCAnnotation *annotation1=[[KCAnnotation alloc]init];
annotation1.title=@"CMJ Studio";
annotation1.subtitle=@"Kenshin Cui's Studios";
annotation1.coordinate=location1;
annotation1.image=[UIImage imageNamed:@"icon_pin_floating.png"];
[_mapView addAnnotation:annotation1];
CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
KCAnnotation *annotation2=[[KCAnnotation alloc]init];
annotation2.title=@"Kenshin&Kaoru";
annotation2.subtitle=@"Kenshin Cui's Home";
annotation2.coordinate=location2;
annotation2.image=[UIImage imageNamed:@"icon_paopao_waterdrop_streetscape.png"];
[_mapView addAnnotation:annotation2];
#pragma mark - 地图控件代理方法
#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id&MKAnnotation&)annotation{
//由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图
if ([annotation isKindOfClass:[KCAnnotation class]]) {
static NSString *key1=@"AnnotationKey1";
MKAnnotationView *annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];
//如果缓存池中不存在则新建
if (!annotationView) {
annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:key1];
annotationView.canShowCallout=true;//允许交互点击
annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量
annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"icon_classify_cafe.png"]];//定义详情左侧视图
//修改大头针视图
//重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)
annotationView.annotation=
annotationView.image=((KCAnnotation *)annotation).//设置大头针视图的图片
return annotationV
运行效果:
在MapKit框架中除了MKAnnotationView之外还有一个MKPinAnnotationView,它是MKAnnotationView的子类,相比MKAnnotationView多了两个属性pinColor和animationDrop,分别用于设置大头针视图颜色和添加大头针动画。
扩展--自定义大头针弹详情视图
通过上面的示例不难看出MKAnnotationView足够强大(何况还有MKPinAnnotationView),很多信息都可以进行设置,但是唯独不能修改大头针描述详情视图(仅仅支持详情中左右视图内容)。要实现这个需求目前开发中普遍采用的思路就是:
a.点击一个大头针A时重新在A的坐标处添加另一个大头针B(注意此时将A对应的大头针视图canShowCallout设置为false)作为大头针详情模型,然后在- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id &MKAnnotation&)代理方法中判断大头针类型,如果是B则重写MKAnnotationView(可以自定义一个类C继承于MKAnnotationView),返回自定义大头针视图C。
b.定义大头针视图C继承于MKAnnotationView(或者MKPinAnnotationView),在自定义大头针视图中添加自己的控件,完成自定义布局。
在使用百度地图客户端时当点击一个搜索位置时可以看到此位置的评价等信息,视图效果大概如下:
下面不妨试着实现一下这个效果:
大头针模型:KCAnnotation.h//
KCAnnotation.h
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &Foundation/Foundation.h&
#import &MapKit/MapKit.h&
@interface KCAnnotation : NSObject&MKAnnotation&
@property (nonatomic) CLLocationCoordinate2D
@property (nonatomic, copy) NSString *
@property (nonatomic, copy) NSString *
#pragma mark 自定义一个图片属性在创建大头针视图时使用
@property (nonatomic,strong) UIImage *
#pragma mark 大头针详情左侧图标
@property (nonatomic,strong) UIImage *
#pragma mark 大头针详情描述
@property (nonatomic,copy) NSString *
#pragma mark 大头针右下方星级评价
@property (nonatomic,strong) UIImage *
弹出详情大头针模型:KCCalloutAnnotation.h//
KCCalloutAnnotation.h
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import &UIKit/UIKit.h&
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
@interface KCCalloutAnnotation : NSObject&MKAnnotation&
@property (nonatomic) CLLocationCoordinate2D
@property (nonatomic, copy,readonly) NSString *
@property (nonatomic, copy,readonly) NSString *
#pragma mark 左侧图标
@property (nonatomic,strong) UIImage *
#pragma mark 详情描述
@property (nonatomic,copy) NSString *
#pragma mark 星级评价
@property (nonatomic,strong) UIImage *
弹出详情大头针视图:KCCalloutAnnotatonView.h//
KCCalloutView.h
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
自定义弹出标注视图
#import &UIKit/UIKit.h&
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
#import "KCCalloutAnnotation.h"
@interface KCCalloutAnnotationView : MKAnnotationView
@property (nonatomic ,strong) KCCalloutAnnotation *
#pragma mark 从缓存取出标注视图
+(instancetype)calloutViewWithMapView:(MKMapView *)mapV
KCCalloutAnnotationView.m//
KCCalloutView.m
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCCalloutAnnotationView.h"
#define kSpacing 5
#define kDetailFontSize 12
#define kViewOffset 80
@interface KCCalloutAnnotationView(){
UIView *_backgroundV
UIImageView *_iconV
UILabel *_detailL
UIImageView *_rateV
@implementation KCCalloutAnnotationView
-(instancetype)init{
if(self=[super init]){
[self layoutUI];
-(instancetype)initWithFrame:(CGRect)frame{
if (self=[super initWithFrame:frame]) {
[self layoutUI];
-(void)layoutUI{
_backgroundView=[[UIView alloc]init];
_backgroundView.backgroundColor=[UIColor whiteColor];
//左侧添加图标
_iconView=[[UIImageView alloc]init];
//上方详情
_detailLabel=[[UILabel alloc]init];
_detailLabel.lineBreakMode=NSLineBreakByWordW
//[_text sizeToFit];
_detailLabel.font=[UIFont systemFontOfSize:kDetailFontSize];
//下方星级
_rateView=[[UIImageView alloc]init];
[self addSubview:_backgroundView];
[self addSubview:_iconView];
[self addSubview:_detailLabel];
[self addSubview:_rateView];
+(instancetype)calloutViewWithMapView:(MKMapView *)mapView{
static NSString *calloutKey=@"calloutKey1";
KCCalloutAnnotationView *calloutView=(KCCalloutAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:calloutKey];
if (!calloutView) {
calloutView=[[KCCalloutAnnotationView alloc]init];
return calloutV
#pragma mark 当给大头针视图设置大头针模型时可以在此处根据模型设置视图内容
-(void)setAnnotation:(KCCalloutAnnotation *)annotation{
[super setAnnotation:annotation];
//根据模型调整布局
_iconView.image=annotation.
_iconView.frame=CGRectMake(kSpacing, kSpacing, annotation.icon.size.width, annotation.icon.size.height);
_detailLabel.text=annotation.
float detailWidth=150.0;
CGSize detailSize= [annotation.detail boundingRectWithSize:CGSizeMake(detailWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kDetailFontSize]} context:nil].
float detailX=CGRectGetMaxX(_iconView.frame)+kS
_detailLabel.frame=CGRectMake(detailX, kSpacing, detailSize.width, detailSize.height);
_rateView.image=annotation.
_rateView.frame=CGRectMake(detailX, CGRectGetMaxY(_detailLabel.frame)+kSpacing, annotation.rate.size.width, annotation.rate.size.height);
float backgroundWidth=CGRectGetMaxX(_detailLabel.frame)+kS
float backgroundHeight=_iconView.frame.size.height+2*kS
_backgroundView.frame=CGRectMake(0, 0, backgroundWidth, backgroundHeight);
self.bounds=CGRectMake(0, 0, backgroundWidth, backgroundHeight+kViewOffset);
主视图控制器:KCMainViewController.m//
KCMainViewController.m
MapKit Annotation
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
-122.406417
39.92 116.39
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
#import "KCAnnotation.h"
#import "KCCalloutAnnotationView.h"
#import "KCCalloutAnnotationView.h"
@interface KCMainViewController ()&MKMapViewDelegate&{
CLLocationManager *_locationM
MKMapView *_mapV
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initGUI];
#pragma mark 添加地图控件
-(void)initGUI{
CGRect rect=[UIScreen mainScreen].
_mapView=[[MKMapView alloc]initWithFrame:rect];
[self.view addSubview:_mapView];
//设置代理
_mapView.delegate=
//请求定位服务
_locationManager=[[CLLocationManager alloc]init];
if(![CLLocationManager locationServicesEnabled]||[CLLocationManager authorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
[_locationManager requestWhenInUseAuthorization];
//用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)
_mapView.userTrackingMode=MKUserTrackingModeF
//设置地图类型
_mapView.mapType=MKMapTypeS
//添加大头针
[self addAnnotation];
#pragma mark 添加大头针
-(void)addAnnotation{
CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(39.95, 116.35);
KCAnnotation *annotation1=[[KCAnnotation alloc]init];
annotation1.title=@"CMJ Studio";
annotation1.subtitle=@"Kenshin Cui's Studios";
annotation1.coordinate=location1;
annotation1.image=[UIImage imageNamed:@"icon_pin_floating.png"];
annotation1.icon=[UIImage imageNamed:@"icon_mark1.png"];
annotation1.detail=@"CMJ Studio...";
annotation1.rate=[UIImage imageNamed:@"icon_Movie_Star_rating.png"];
[_mapView addAnnotation:annotation1];
CLLocationCoordinate2D location2=CLLocationCoordinate2DMake(39.87, 116.35);
KCAnnotation *annotation2=[[KCAnnotation alloc]init];
annotation2.title=@"Kenshin&Kaoru";
annotation2.subtitle=@"Kenshin Cui's Home";
annotation2.coordinate=location2;
annotation2.image=[UIImage imageNamed:@"icon_paopao_waterdrop_streetscape.png"];
annotation2.icon=[UIImage imageNamed:@"icon_mark2.png"];
annotation2.detail=@"Kenshin Cui...";
annotation2.rate=[UIImage imageNamed:@"icon_Movie_Star_rating.png"];
[_mapView addAnnotation:annotation2];
#pragma mark - 地图控件代理方法
#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id&MKAnnotation&)annotation{
//由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图
if ([annotation isKindOfClass:[KCAnnotation class]]) {
static NSString *key1=@"AnnotationKey1";
MKAnnotationView *annotationView=[_mapView dequeueReusableAnnotationViewWithIdentifier:key1];
//如果缓存池中不存在则新建
if (!annotationView) {
annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:key1];
annotationView.canShowCallout=//允许交互点击
annotationView.calloutOffset=CGPointMake(0, 1);//定义详情视图偏移量
annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"icon_classify_cafe.png"]];//定义详情左侧视图
//修改大头针视图
//重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)
annotationView.annotation=
annotationView.image=((KCAnnotation *)annotation).//设置大头针视图的图片
return annotationV
}else if([annotation isKindOfClass:[KCCalloutAnnotation class]]){
//对于作为弹出详情视图的自定义大头针视图无弹出交互功能(canShowCallout=false,这是默认值),在其中可以自由添加其他视图(因为它本身继承于UIView)
KCCalloutAnnotationView *calloutView=[KCCalloutAnnotationView calloutViewWithMapView:mapView];
calloutView.annotation=
return calloutV
#pragma mark 选中大头针时触发
//点击一般的大头针KCAnnotation时添加一个大头针作为所点大头针的弹出详情视图
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
KCAnnotation *annotation=view.
if ([view.annotation isKindOfClass:[KCAnnotation class]]) {
//点击一个大头针时移除其他弹出详情视图
[self removeCustomAnnotation];
//添加详情大头针,渲染此大头针视图时将此模型对象赋值给自定义大头针视图完成自动布局
KCCalloutAnnotation *annotation1=[[KCCalloutAnnotation alloc]init];
annotation1.icon=annotation.
annotation1.detail=annotation.
annotation1.rate=annotation.
annotation1.coordinate=view.annotation.
[mapView addAnnotation:annotation1];
#pragma mark 取消选中时触发
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
[self removeCustomAnnotation];
#pragma mark 移除所用自定义大头针
-(void)removeCustomAnnotation{
[_mapView.annotations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[KCCalloutAnnotation class]]) {
[_mapView removeAnnotation:obj];
在这个过程中需要注意几点:
1.大头针A作为一个普通大头针,其中最好保存自定义大头针视图C所需要的模型以便根据不同的模型初始化视图。
2.自定义大头针视图C的大头针模型B中不需要title、subtitle属性,最好设置为只读;模型中最后保存自定义大头针视图C所需要的布局模型数据。
3.只有点击非B类大头针时才新增自定义大头针,并且增加时要首先移除其他B类大头针避免重叠(一般建议放到取消大头针选择的代理方法中)。
4.通常在自定义大头针视图C设置大头针模型时布局界面,此时需要注意新增大头针的位置,通常需要偏移一定的距离才能达到理想的效果。
运行效果:
使用自带的地图应用
除了可以使用MapKit框架进行地图开发,对地图有精确的控制和自定义之外,如果对于应用没有特殊要求的话选用苹果自带的地图应用也是一个不错的选择。使用苹果自带的应用时需要用到MapKit中的MKMapItem类,这个类有一个openInMapsWithLaunchOptions:动态方法和一个openMapsWithItems: launchOptions:静态方法用于打开苹果地图应用。第一个方法用于在地图上标注一个位置,第二个方法除了可以标注多个位置外还可以进行多个位置之间的驾驶导航,使用起来也是相当方便。在熟悉这两个方法使用之前有必要对两个方法中的options参数做一下简单说明:
MKLaunchOptionsDirectionsModeKey
路线模式,常量
MKLaunchOptionsDirectionsModeDriving& 驾车模式MKLaunchOptionsDirectionsModeWalking 步行模式
MKLaunchOptionsMapTypeKey
地图类型,枚举
MKMapTypeStandard :标准模式MKMapTypeSatellite :卫星模式MKMapTypeHybrid& :混合模式
MKLaunchOptionsMapCenterKey
中心点坐标,CLLocationCoordinate2D类型
MKLaunchOptionsMapSpanKey
地图显示跨度,MKCoordinateSpan 类型
MKLaunchOptionsShowsTrafficKey
是否 显示交通状况,布尔型
MKLaunchOptionsCameraKey
3D地图效果,MKMapCamera类型注意:此属性从iOS7及以后可用,前面的属性从iOS6开始可用
单个位置的标注
下面的代码演示了如何在苹果自带地图应用上标记一个位置,首先根据反地理编码获得一个CLPlacemark位置对象,然后将其转换为MKPlacemark对象用于MKMapItem初始化,最后调用其openInMapsWithLaunchOptions:打开地图应用并标记://
KCMainViewController.m
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
_geocoder=[[CLGeocoder alloc]init];
[self location];
#pragma mark 在地图上定位
-(void)location{
//根据“北京市”进行地理编码
[_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *clPlacemark=[placemarks firstObject];//获取第一个地标
MKPlacemark *mkplacemark=[[MKPlacemark alloc]initWithPlacemark:clPlacemark];//定位地标转化为地图的地标
NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
MKMapItem *mapItem=[[MKMapItem alloc]initWithPlacemark:mkplacemark];
[mapItem openInMapsWithLaunchOptions:options];
运行效果:
标记多个位置
如果要标记多个位置需要调用MKMapItem的静态方法,下面的代码演示中需要注意,使用CLGeocoder进行定位时一次只能定位到一个位置,所以第二个位置定位放到了第一个位置获取成功之后。//
KCMainViewController.m
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
_geocoder=[[CLGeocoder alloc]init];
[self listPlacemark];
-(void)listPlacemark{
//根据“北京市”进行地理编码
[_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *clPlacemark1=[placemarks firstObject];//获取第一个地标
MKPlacemark *mkPlacemark1=[[MKPlacemark alloc]initWithPlacemark:clPlacemark1];
//注意地理编码一次只能定位到一个位置,不能同时定位,所在放到第一个位置定位完成回调函数中再次定位
[_geocoder geocodeAddressString:@"郑州市" completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *clPlacemark2=[placemarks firstObject];//获取第一个地标
MKPlacemark *mkPlacemark2=[[MKPlacemark alloc]initWithPlacemark:clPlacemark2];
NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)};
//MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//当前位置
MKMapItem *mapItem1=[[MKMapItem alloc]initWithPlacemark:mkPlacemark1];
MKMapItem *mapItem2=[[MKMapItem alloc]initWithPlacemark:mkPlacemark2];
[MKMapItem openMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];
运行效果:
要使用地图导航功能在自带地图应用中相当简单,只要设置参数配置导航模式即可,例如在上面代码基础上设置驾驶模式,则地图应用会启动驾驶模式计算两点之间的距离同时对路线进行规划。//
KCMainViewController.m
Created by Kenshin Cui on 14/3/27.
Copyright (c) 2014年 Kenshin Cui. All rights reserved.
#import "KCMainViewController.h"
#import &CoreLocation/CoreLocation.h&
#import &MapKit/MapKit.h&
@interface KCMainViewController ()
@property (nonatomic,strong) CLGeocoder *
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
_geocoder=[[CLGeocoder alloc]init];
[self turnByTurn];
-(void)turnByTurn{
//根据“北京市”地理编码
[_geocoder geocodeAddressString:@"北京市" completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *clPlacemark1=[placemarks firstObject];//获取第一个地标
MKPlacemark *mkPlacemark1=[[MKPlacemark alloc]initWithPlacemark:clPlacemark1];
//注意地理编码一次只能定位到一个位置,不能同时定位,所在放到第一个位置定位完成回调函数中再次定位
[_geocoder geocodeAddressString:@"郑州市" completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *clPlacemark2=[placemarks firstObject];//获取第一个地标
MKPlacemark *mkPlacemark2=[[MKPlacemark alloc]initWithPlacemark:clPlacemark2];
NSDictionary *options=@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard),MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
//MKMapItem *mapItem1=[MKMapItem mapItemForCurrentLocation];//当前位置
MKMapItem *mapItem1=[[MKMapItem alloc]initWithPlacemark:mkPlacemark1];
MKMapItem *mapItem2=[[MKMapItem alloc]initWithPlacemark:mkPlacemark2];
[MKMapItem openMapsWithItems:@[mapItem1,mapItem2] launchOptions:options];
运行效果:
注意:其实如果不用苹果自带的地图应用也可以实现地图导航,MapKit中提供了MKDirectionRequest对象用于计算路线,提供了MKDirections用于计算方向,这样一来只需要调用MKMapView的addOverlay等方法添加覆盖物即可实现类似的效果,有兴趣的朋友可以试一下。
由于定位和地图框架中用到了诸多类,有些初学者容易混淆,下面简单对比一下。
CLLocation:用于表示位置信息,包含地理坐标、海拔等信息,包含在CoreLoaction框架中。
MKUserLocation:一个特殊的大头针,表示用户当前位置。
CLPlacemark:定位框架中地标类,封装了详细的地理信息。
MKPlacemark:类似于CLPlacemark,只是它在MapKit框架中,可以根据CLPlacemark创建MKPlacemark。

我要回帖

更多关于 松下传真机 的文章

 

随机推荐