最新消息:20210917 已从crifan.com换到crifan.org

给Your Second iOS App:BirdWatching添加地图的支持

iOS crifan 2643浏览 0评论

已经给Your Second iOS App:BirdWatching添加了Location Services了,现在继续给其添加地图显示的支持。


网上找了下,找到官网的资料:

Location Awareness Programming Guide – Displaying Maps

所以,先去学习相关iOS中的地图的基本知识。

1. 地球是圆的球,映射到一个平面,用的是“Mercator地图投影法”。

2.iOS中的Map Kit中有三种坐标系统:

 

3.如果涉及不同坐标系转换,可以用下面的函数:

Convert from

Convert to

Conversion routines

Map coordinates

Points

convertCoordinate:toPointToView: (MKMapView)

convertRegion:toRectToView: (MKMapView)

Map coordinates

Map points

MKMapPointForCoordinate

Map points

Map coordinates

MKCoordinateForMapPoint

MKCoordinateRegionForMapRect

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到对应位置:

add map view

差点忘了,需要先去添加MapKit.framework:

add 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;

然后运行效果如图:

can show google map

即,就可以正常显示google地图了。

只不过有个小问题,鼠标滚轮键,无法放大缩小地图,目前只能通过双击鼠标实现放大地图的功能。

6.接下来,想办法把当前坐标传递进去,让地图自动定位到当前位置。

然后找到了MKMapView的showsUserLocation,然后添加设置:

self.locationMapView.showsUserLocation = YES;

然后运行结果,就可以自动定位到当前的位置了:

show current location

7.不过,对于上述的经纬度:

+37,-122

到底对应的是什么位置,找了下,最后从:

http://www.gpsspg.com/maps.htm

中找到了:

search out real location

的确是美国的California的位置。

而此位置,正是apple总部所在地:

苹果股份有限公司,简称苹果公司,总部位于美国硅谷。关于硅谷:位于美国加利福尼亚州的旧金山经圣克拉拉至圣何塞近50公里的一条狭长地带

所以,很明显,apple地图默认初始地址,是apple总部的位置。

8.那接下来,希望找到当前中国苏州的位置,然后将其设置到地图中,然后让其定位到此位置。

继续到上述网站中找到苏州独墅湖中间位置是:+31,+120的位置。

所以,接着就是想办法把此坐标设置过去。

找到了相关的函数:

setCenterCoordinate:animated:

但是其参数类型是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;

}

是可以实现将地图中间位置切换到指定的坐标的:

coordinate ok can center

所以验证了,只要上述坐标值赋值正确,是可以正确显示位置的。

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.70549774169922

GPS经纬度:

纬度: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];

最终,可以正确定位到相应的位置了:

valid coordinate

 

所以:初始化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的值了:

lat logi update ok

【总结】

添加MKMapView的核心是,先加framework,然后加头文件。

最后调用几个相关的类,CoreLocation等,添加对应的delegate,实现自己需要的功能。即可。

转载请注明:在路上 » 给Your Second iOS App:BirdWatching添加地图的支持

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
93 queries in 0.184 seconds, using 23.45MB memory