已经给Your Second iOS App:BirdWatching添加了Location Services了,现在继续给其添加地图显示的支持。
网上找了下,找到官网的资料:
Location Awareness Programming Guide – Displaying Maps
所以,先去学习相关iOS中的地图的基本知识。
1. 地球是圆的球,映射到一个平面,用的是“Mercator地图投影法”。
2.iOS中的Map Kit中有三种坐标系统:
- map coordinate:包括了经度和纬度,涉及类,点:
CLLocationCoordinate2D,范围/区域:
MKCoordinateSpan
andMKCoordinateRegion
- map point:x和y值。涉及,点:
MKMapPoint,
范围和区域:MKMapSize
andMKMapRect
- point :
UIView
中的点。涉及类,点:CGPoint
,范围和区域:CGSize
andCGRect
3.如果涉及不同坐标系转换,可以用下面的函数:
Convert from | Convert to | Conversion routines |
Map coordinates | Points | convertCoordinate:toPointToView: (MKMapView) convertRegion:toRectToView: (MKMapView) |
Map coordinates | Map points | |
Map points | Map coordinates | |
Map points | Points | pointForMapPoint: (MKOverlayView) rectForMapRect: (MKOverlayView) |
Points | Map coordinates | convertPoint:toCoordinateFromView: (MKMapView) convertRect:toRegionFromView: (MKMapView) |
Points | Map points | mapPointForPoint: (MKOverlayView) mapRectForRect: (MKOverlayView) |
4.接下来就去试试如何使用类:MKMapView
。
参考教程,从IB中拖动一个Map View到对应位置:
差点忘了,需要先去添加MapKit.framework:
5.然后去参考MapViewController.m:
(1)在AddSightingViewController.h中添加了:
#import <MapKit/MapKit.h> @property (nonatomic) IBOutlet MKMapView *locationMapView;
(2)并且将locationMapView关联到之前UITableView中的MKMapView。
(3)在AddSightingViewController.m中的viewDidLoad添加:
self.locationMapView.mapType = MKMapTypeStandard;
然后运行效果如图:
即,就可以正常显示google地图了。
只不过有个小问题,鼠标滚轮键,无法放大缩小地图,目前只能通过双击鼠标实现放大地图的功能。
6.接下来,想办法把当前坐标传递进去,让地图自动定位到当前位置。
然后找到了MKMapView的showsUserLocation,然后添加设置:
self.locationMapView.showsUserLocation = YES;
然后运行结果,就可以自动定位到当前的位置了:
7.不过,对于上述的经纬度:
+37,-122
到底对应的是什么位置,找了下,最后从:
http://www.gpsspg.com/maps.htm
中找到了:
的确是美国的California的位置。
而此位置,正是apple总部所在地:
苹果股份有限公司,简称苹果公司,总部位于美国硅谷。关于硅谷:位于美国加利福尼亚州的旧金山经圣克拉拉至圣何塞近50公里的一条狭长地带
所以,很明显,apple地图默认初始地址,是apple总部的位置。
8.那接下来,希望找到当前中国苏州的位置,然后将其设置到地图中,然后让其定位到此位置。
继续到上述网站中找到苏州独墅湖中间位置是:+31,+120的位置。
所以,接着就是想办法把此坐标设置过去。
找到了相关的函数:
但是其参数类型是CLLocationCoordinate2D,所以接着就是去初始化此类型变量了。
结果是,测试了如下代码:
self.locationMapView.mapType = MKMapTypeStandard; //self.locationMapView.showsUserLocation = YES; location2D.longitude = 37; location2D.latitude = 120; [self.locationMapView setCenterCoordinate:location2D animated:YES];
但是运行出错。
9.后来经过折腾,试了,把相关代码剪切到,放到didUpdateToLocation中去:
#pragma mark - #pragma mark CLLocationManagerDelegate -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ //NSString *locationDesciption = [[NSString alloc] initWithString:newLocation.description]; self.locationInput.text = [[NSString alloc] initWithString:newLocation.description]; //location2D.longitude = 37; //location2D.latitude = 120; //[self.locationMapView setCenterCoordinate:location2D animated:YES]; [self.locationMapView setCenterCoordinate:newLocation.coordinate animated:YES]; self.locationManager.delegate = nil; }
是可以实现将地图中间位置切换到指定的坐标的:
所以验证了,只要上述坐标值赋值正确,是可以正确显示位置的。
10.所以接着去确保坐标初始化正确。
然后试了试:
CLLocationDegrees longitude = 37; CLLocationDegrees latitude = 120; location2D.longitude = longitude; location2D.latitude = latitude; [self.locationMapView setCenterCoordinate:location2D animated:YES]; //[self.locationMapView setCenterCoordinate:newLocation.coordinate animated:YES];
也还是不行,会出错。
11.继续想办法初始化CLLocationCoordinate2D变量。
找到了CLLocationCoordinate2DMake,
调试了半天,中间出现过错误:
2012-09-06 12:57:59.102 BirdWatching[1170:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid Coordinate +120.70120000, +31.27210000' *** First throw call stack: (0x14b0022 0x1022cd6 0x14afee1 0x2ba25 0x67c1 0xf6fda 0xf6956 0xf5449 0xf1b9a 0x1484970 0x14241c1 0x13e7967 0x13e6d84 0x13e6c9b 0x16c67d8 0x16c688a 0x185626 0x29bd 0x2925) terminate called throwing an exception(lldb)
说明还是坐标值,不对。
最终可以运行的坐标,是从:
http://www.gpsspg.com/maps.htm
找到了某个值,比如:
谷歌纬度经度:
31.27006030476515,120.70549774169922GPS经纬度:
纬度:31.2721052962652
经度:120.701179385199
北纬:31°16′19.58″
东经:120°42′4.25″
靠近:Dushuhu Tunnel, Wuzhong, Suzhou, Jiangsu, China
然后把上述的“谷歌纬度经度,即:
纬度:31.27006030476515
经度:120.70549774169922
分别赋值进去:
// CLLocationDegrees longitude = 37; // CLLocationDegrees latitude = 120; // // location2D.longitude = longitude; // location2D.latitude = latitude; // [self.locationMapView setCenterCoordinate:location2D animated:YES]; // CLLocationCoordinate2D customLoc2D = CLLocationCoordinate2DMake(120.70549774169922, 31.27006030476515); // CLLocationCoordinate2D customLoc2D_2 = CLLocationCoordinate2DMake(120.701179385199, 31.2721052962652); //CLLocationCoordinate2D customLoc2D_4 = CLLocationCoordinate2DMake(120.7012, 31.2721); CLLocationCoordinate2D customLoc2D_5 = CLLocationCoordinate2DMake(31.27006030476515, 120.70549774169922); [self.locationMapView setCenterCoordinate:customLoc2D_5 animated:YES]; //CLLocationCoordinate2D customLoc2D_3 =newLocation.coordinate; //[self.locationMapView setCenterCoordinate:customLoc2D_3 animated:YES];
最终,可以正确定位到相应的位置了:
所以:初始化CLLocationCoordinate2D之类的变量的时候,一定要是合法的坐标值。而且尤其要注意,经度和纬度不要搞错了。
总之,错误的经纬度值,会造成错误:
Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Invalid Coordinate +120.70120000, +31.27210000’
12. 关于如何获得合法的坐标值,可参考:
iOS中如何获得合法的CLLocationCoordinate2D类型的坐标值 + 把CLLocation转换为CLLocationCoordinate2D
13. 而关于后续继续折腾,把坐标值转换为可读的地理位置文本信息,感兴趣的可参考:
【已解决】iOS中,从已有的坐标值,获得相应的地理位置描述信息/文本描述
14.然后又继续折腾,支持当地图位置变化后,当前可以可以实时检测得到。
实现了相关的函数:
#pragma mark - #pragma mark MKMapViewDelegate - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{ self.locationInput.text = [[NSString alloc] initWithString:userLocation.description]; } -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ self.locationInput.text = @"captured change"; }
但是调试了半天,竟然始终无法执行到此两个函数。
最后,才发现,自己是忘了设置delegate了。
然后去viewDidLoad中添加了:
self.locationMapView.delegate = self;
最终,才得以成功调用上述两个函数。
15. 剩下的功能,可以考虑把坐标值转换为字符串,赋值给location位置。
最后,通过如下代码:
#pragma mark - #pragma mark MKMapViewDelegate - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{ //self.locationInput.text = [[NSString alloc] initWithString:userLocation.description]; } -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{ CLLocationCoordinate2D curLoc2D = self.locationMapView.centerCoordinate; NSString *locStr = [[NSString alloc] initWithFormat:@"<lat=%.4f,logi=%.4f>", curLoc2D.latitude,curLoc2D.longitude]; self.locationInput.text = locStr; //self.locationInput.text = @"captured change"; }
可以实现,当地图位置变化,可以实时更新上述latitude和longitude的值了:
【总结】
添加MKMapView的核心是,先加framework,然后加头文件。
最后调用几个相关的类,CoreLocation等,添加对应的delegate,实现自己需要的功能。即可。