调用地图功能的实现
一:苹果自带地图
学习如逆水行舟,不进则退。古人告诉我们要不断的反思和总结,日思则日精,月思则月精,年思则年精。只有不断的尝试和总结,才能让我们的工作和生活更加 轻松愉快和美好。连着做了两个大的商城外包项目,智慧城市,搜牧通,花费了近四个月的时间,终于在反复修改后完美收工。期间的困难自不必说,以后多多总结 和沟通吧。百度地图的使用之前已经发表了一篇文章,说的很详细了,这里不再涉及,言归正传,我们说一下如何调用苹果自带的地图
第一步:导入地图文件 #import <MapKit/MapKit.h>
第二步:获取当前位置和目的地的经纬度,然后打开地图即可
//获取当前位置
1 MKMapItem *mylocation = [MKMapItem mapItemForCurrentLocation];
//当前经维度
1 float currentLatitude=mylocation.placemark.location.coordinate.latitude; 2 3 float currentLongitude=mylocation.placemark.location.coordinate.longitude; 4 5 6 7 CLLocationCoordinate2D coords1 = CLLocationCoordinate2DMake(currentLatitude,currentLongitude);
//目的地位置
1 coordinate.latitude=[[dataSource objectForKey:@"lat"] floatValue]; 2 3 coordinate.longitude=[[dataSource objectForKey:@"lng"] floatValue]; 4 5 6 7 8 9 CLLocationCoordinate2D coords2 = coordinate; 10 11 12 13 // ios6以下,调用google map 14 15 if (SYSTEM_VERSION_LESS_THAN(@"6.0")) 16 17 { 18 19 NSString *urlString = [[NSString alloc] initWithFormat:@"http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f&dirfl=d", coords1.latitude,coords1.longitude,coords2.latitude,coords2.longitude]; 20 21 NSURL *aURL = [NSURL URLWithString:urlString]; 22 23 //打开网页google地图 24 25 [[UIApplication sharedApplication] openURL:aURL]; 26 27 } 28 29 else 30 31 // 直接调用ios自己带的apple map 32 33 { 34 35 //当前的位置 36 37 MKMapItem *currentLocation = [MKMapItem mapItemForCurrentLocation]; 38 39 //起点 40 41 //MKMapItem *currentLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:coords1 addressDictionary:nil]]; 42 43 //目的地的位置 44 45 MKMapItem *toLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:coords2 addressDictionary:nil]]; 46 47 48 49 toLocation.name = @"目的地"; 50 51 NSString *myname=[dataSource objectForKey:@"name"]; 52 53 if (![XtomFunction xfunc_check_strEmpty:myname]) 54 55 { 56 57 toLocation.name =myname; 58 59 } 60 61 62 63 NSArray *items = [NSArray arrayWithObjects:currentLocation, toLocation, nil]; 64 65 NSDictionary *options = @{ MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving, MKLaunchOptionsMapTypeKey: [NSNumber numberWithInteger:MKMapTypeStandard], MKLaunchOptionsShowsTrafficKey:@YES }; 66 67 //打开苹果自身地图应用,并呈现特定的item 68 69 [MKMapItem openMapsWithItems:items launchOptions:options]; 70 71 } 72 73
通过这两步就可以轻松的开启苹果自带地图导航,感觉真是挺不错的,唯一的缺点是开启地图获取路线信息耗费的手机流量比较大,最好在wifi条件下调用。如果不是必须,尽量还是用高德或者百度自带的地图就好。
二:百度地图
一:首先我们有一点与用googlemap开发的不同,需要创建BMKMapManager管理应用程序的map,如果没有这个类,地图则不能够显示。
下面红色的字体是自己在百度官方申请的地图api——key;
1 BMKMapManager *_mapManager = [[BMKMapManager alloc] init]; 2 3 BOOL ret = [_mapManager start:@"C3252C69EDB6D21A10B3FC9657FD1DDC7E0000**"generalDelegate:self]; 4 5 if (!ret) { 6 7 NSLog(@"manager start failed!"); 8 9 }
二:在view中添加BMKMapView,同时设置BMKMapViewDelegate,添加annotation(记录兴趣点,BMKAnnotation),同时每个兴趣点可以设置其title(设置annotation的标题),以及subtitle(子标题)。
1 @interface MapBaiDu : UIViewController <BMKMapViewDelegate> { } 2 3 @property (nonatomic, strong) BMKMapView *_mapView; 4 5 @end 6 7 8 - (void)viewDidLoad { 9 10 11 12 _mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, 39, 320, 377)]; //创建MKMapView 13 14 [self.view addSubview:_mapView]; 15 16 [_mapView release]; 17 18 19 20 _mapView.delegate = self; //设置代理 21 22 _mapView.showsUserLocation = YES; //设置为可以显示用户位置 23 24 CLLocationCoordinate2D coordinate; //设定经纬度 25 26 coordinate.latitude = 40.027283; //纬度 27 28 coordinate.longitude = 116.313217; //经度 29 30 31 32 BMKCoordinateRegion viewRegion = BMKCoordinateRegionMake(coordinate, BMKCoordinateSpanMake(1.0,1.0)); 33 34 BMKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion]; 35 36 [_mapView setRegion:adjustedRegion animated:YES]; 37 38 }
上 面最后一行 :设置当前地图的经纬度范围,设定的该范围可能会被调整为适合地图窗口显示的范围。region是BMKMapView的一个属性,类型 BMKCoordinateRegion ,这行的意思是创建一个以coordinate为中心,上下左右个0.5个经(纬)度。但是这时我们需要注意一个问题就是,创建的区域是一个正方形,并不 符合我们所需要的BMKMapView比例;之后用方法regionThatFits调整显示范围。
1 ///表示一个经纬度区域 2 3 typedef struct { 4 5 CLLocationCoordinate2D center; ///< 中心点经纬度坐标 6 7 BMKCoordinateSpan span; ///< 经纬度范围 8 9 } BMKCoordinateRegion; 10 11 12 13 14 15 ///表示一个经纬度范围 16 17 typedef struct { 18 19 CLLocationDegrees latitudeDelta; ///< 纬度范围 20 21 CLLocationDegrees longitudeDelta; ///< 经度范围 22 23 } BMKCoordinateSpan;
三:下面我们简单说一下delegate
1:地图区域改变时候调用函数:
1 - (void)mapView:(BMKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
2:annotation
*根据anntation生成对应的View
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation;
*当mapView新添加annotation views时,调用此接口
- (void)mapView:(BMKMapView *)mapView didAddAnnotationViews:(NSArray *)views;
*当选中一个annotation views时,调用此接口
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view;
*当取消选中一个annotation views时,调用此接口
- (void)mapView:(BMKMapView *)mapView didDeselectAnnotationView:(BMKAnnotationView *)view;
而annotation分为两部分:BMKAnotation该类为标注点的protocol,提供了标注类的基本信息函数,title和subtitle分别是标题和子标题;同时可以设置标注的左边,在拖曳时候会被调用setCoordinate;
BMKAnnotationView 为标注点显示视图类,该类继承UIView,可以设置此view显示的图像,可以设置centerOffset(中心的位置,正的偏移使view超右下方 移动,负的朝右上方移动,单位为像素),还可以设置calloutOffset改变淡出的气泡位置(正的偏移使view超右下方移动,负的朝左上方移动, 单位是像素)。还可以设置其触摸事件,默认情况下为YES,可以选中,也可以是enabled = NO。其他的属性还 有:selected,canShowCallout,leftCalloutAccessoryView,rightCalloutAccessoryView。 等等
四:当地图view定位时调用函数:
*当取消选中一个annotation views时,调用此接口
- (void)mapView:(BMKMapView *)mapView didDeselectAnnotationView:(BMKAnnotationView *)view;
*在地图View将要启动定位时,会调用此函数
- (void)mapViewWillStartLocatingUser:(BMKMapView *)mapView;
*在地图View停止定位后,会调用此函数
- (void)mapViewDidStopLocatingUser:(BMKMapView *)mapView;
*定位失败后,会调用此函数
- (void)mapView:(BMKMapView *)mapView didFailToLocateUserWithError:(NSError *)error;
*用户位置更新后,会调用此函数
- (void)mapView:(BMKMapView *)mapView didUpdateUserLocation:(BMKUserLocation *)userLocation;
五:当有overlay(阴影标示某一个区域)生成或者新添加的时候调用此接口
*根据overlay生成对应的View
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id <BMKOverlay>)overlay;
*当mapView新添加overlay views时,调用此接口
- (void)mapView:(BMKMapView *)mapView didAddOverlayViews:(NSArray *)overlayViews;
六:当点击annotation view弹出的泡泡时,调用此接口
*当点击annotation view弹出的泡泡时,调用此接口
- (void)mapView:(BMKMapView *)mapView annotationViewForBubble:(BMKAnnotationView *)view;
九:annotation view有许多不同的状态,在不同状态的时候我们都可以设置不同的操作,拖动annotation view时view的状态变化
1 - (void)mapView:(BMKMapView *)mapView annotationView:(BMKAnnotationView *)view didChangeDragState:(BMKAnnotationViewDragState)newState 2 3 fromOldState:(BMKAnnotationViewDragState)oldState; 4 5 6 7 8 9 enum { 10 11 BMKAnnotationViewDragStateNone = 0, ///< 静止状态. 12 13 BMKAnnotationViewDragStateStarting, ///< 开始拖动 14 15 BMKAnnotationViewDragStateDragging, ///< 拖动中 16 17 BMKAnnotationViewDragStateCanceling, ///< 取消拖动 18 19 BMKAnnotationViewDragStateEnding ///< 拖动结束 20 21 }; 22 23 24 25 typedef NSUInteger BMKAnnotationViewDragState;
三:高德地图
之前工作在一家智能设备的公司,做过一个亲友定位监控系统,类似现在比较流行的360儿童手环。所以这里简单介绍定位与地图。
iOS设备提供三种不同定位途径,蜂窝式移动电话基站定位;WiFi定 位,通过查询一个WiFi路由器的地理位置信息,比较省电;GPS卫星定位,通过3~4颗卫星定位,最为准确,但是耗电量大。iOS系统如果能够接收 GPS信息,那么设备优先采用GPS,其次是WiFi,最后是基站,开发人员不能选择哪种定位方式。
定位服务使用CoreLocation框架,主要使用CLLocationMananger、 CLLocationManangerDelegate和CLLocation三个类,CLLocationMananger是定位服务管理类,获取设备 的位置信息,CLLocationManangerDelegate是代理协议,CLLocation封装了位置信息。
这里要注意,CLLocationManangerDelegate 的locationManager:didUpdateToLocation:fromLocation:方法得到的坐标是火星坐标,这个原因你懂得,所 以需要转换成真实的地理坐标。我使用的是一个第三方的CSqlite类,有一个转换坐标的数据库,你调用就可以转换为正确坐标了。
得到经纬度后,要进行地理位置信息反编码,使用CLGeocoder类实现,将地理坐标转换为地理文字描述信息,这些文字描述信息被封装在CLPlacemark类中。
当然给定地理信息的文字描述,也可以进行地理信息编码查询,转换为地理坐标,也是采用CLGeocoder类。
1 // 在范围内返回1,不在返回0 2 -(int)mutableBoundConrtolAction:(NSMutableArray *)arrSome:(CLLocationCoordinate2D )myCoordinate4{ 3 int n=arrSome.count; 4 float vertx[n]; 5 float verty[n]; 6 for (int i=0; i<arrSome.count; i++) { 7 //MyPoint类存储的是经度和纬度 8 vertx[i]=((MyPoint *)(arrSome[i])).x; 9 verty[i]=((MyPoint *)(arrSome[i])).y; 10 } 11 if (arrSome.count==0) { 12 13 return 1; 14 } 15 BOOL i=pnpoly(arrSome.count, vertx, verty, myCoordinate4.latitude, myCoordinate4.longitude); 16 17 18 if (i) { 19 return 1; 20 }else{ 21 return 0; 22 } 23 24 25 return 1; 26 } 27 //多边形由边界的坐标点所构成的数组组成,参数格式 该数组的count, 多边形边界点x坐标 的组成的数组,多边形边界点y坐标 的组成的数组,需要判断的点的x坐标,需要判断的点的y坐标 28 BOOL pnpoly (int nvert, float *vertx, float *verty, float testx, float testy) { 29 int i, j; 30 BOOL c=NO; 31 for (i = 0, j = nvert-1; i < nvert; j = i++) { 32 33 if ( ( (verty[i]>testy) != (verty[j]>testy) ) && 34 (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) 35 c = !c; 36 } 37 return c; 38 }
地图我目前用过系统、百度以及高德,开发人员使用都是差不多的,下面的代码涉及的类都是高德地图api提供的类。
我之前做项目,使用高德地图,做到后期,项目会出现闪退,后来查出是地图区域内存的问题,然后重新布局了地图区域,使得每一个地图区域能够及时销毁,虽然闪退周期明显延长,但是还是存在,这里不知道是何原因,说来惭愧。
1 -(void)SetMapRegion:(CLLocationCoordinate2D)myCoordinate 2 { 3 MACoordinateRegion theRegion = { {0.0, 0.0 }, { 0.0, 0.0 } }; 4 theRegion.center=myCoordinate; 5 [self.m_map setScrollEnabled:YES]; 6 theRegion.span.longitudeDelta = 0.01f; 7 theRegion.span.latitudeDelta = 0.01f; 8 [self.m_map setRegion:theRegion animated:YES]; 9 }
1 -(void)panMap:(NSString *)direction{ 2 CLLocationCoordinate2D changeCoordinate=self.m_map.centerCoordinate; 3 CGPoint changePoint=[self.m_map convertCoordinate:changeCoordinate toPointToView:self.m_map]; 4 5 if ([direction isEqualToString:@"up"]) { 6 changePoint.y=changePoint.y+50; 7 8 }else if ([direction isEqualToString:@"down"]) { 9 changePoint.y=changePoint.y-50; 10 }else if ([direction isEqualToString:@"left"]) { 11 changePoint.x=changePoint.x-50; 12 }else if ([direction isEqualToString:@"right"]) { 13 changePoint.x=changePoint.x+50; 14 } 15 changeCoordinate=[self.m_map convertPoint:changePoint toCoordinateFromView:self.m_map]; 16 [self.m_map setCenterCoordinate:changeCoordinate animated:YES]; 17 }
1 -(void)isAtCurrentRegion:(CLLocationCoordinate2D)coordiante{ 2 3 CGPoint point=[self.m_map convertCoordinate:coordiante toPointToView:self.view]; 4 if ((point.x<0)||(point.y<0)||(point.x>WScreen)||(point.y>HScreen)) { 5 // 如果不在 设置该点为地图中心点 6 [self SetMapRegion:coordiante]; 7 } 8 9 10 }
系统地图使用MapKit框架,核心是MKMapView类,显示地图只要添加MKMapView实例就可以了。如果要实现在地图上添加标注点, 第以是触发添加动作,第二实现MKMapViewDelegate的mapView:viewForAnnotation:完成添加标注。
高德地图实现的原理也是一样的,高德地图使用的是MAMapKit框架。 对于annotation,一般会自定义一个继承NSobject并且实现了maannotation协议的类,然后使用mapview的 addAnnotation:方法就可以。MKReverseGeocoder类可以实现coordinate的反编码,这里需要实现它的代理,把得到的 地理文字描述信息赋给annotation。这里需要实现代理的mapView:viewForAnnotation:方法,一个标注其实就是一个 MAAnnotationView,标注有点类似tableviewcell,这里也有重用机制。实现代理的 mapView:annotationView:calloutAccessoryControlTapped:方法可以响应 leftCalloutAccessoryView或者rightCalloutAccessoryView的点击事件,不过这个accessory view必须继承自UIControl。
MAPolyline类定义一个由多个点相连的多段线,点与点之间尾部想 连但第一点与最后一个点不相连, 通常MAPolyline是MAPolylineView的model,它提供了两个方法polylineWithPoints:count:、 polylineWithCoordinates:count:用来添加线条,然后再通过map view的addOverlay:方法把Polyline实例添加进去,最后实现mapviewdelegate的 mapView:viewForOverlay:方法就可以了。注意如果一开始添加的不是coordinate,而是point,可以通过map view的convertPoint:toCoordinateFromView:方法进行转换。
MAPolygon类定义的就是一个不规则的由多个点组成的闭合多边形, 点与点之间按顺序尾部相连, 第一个点与最后一个点相连, 通常MAPolygon是MAPolygonView的model,首先需要添加坐标点的数组,可以使用 polygonWithCoordinates:count:方法或者polygonWithPoints:count:方法,然后把这个polygon 通过addOverlay:方法添加到map view上就可以了。然后可以在mapviewdelegate里面的mapView:viewForOverlay:方法里面给 MAPolygonView的属性赋值,这样一个完整的多边形就出来了。
不管是高德地图还是百度地图等第三方,都会有一个mapsearchkit,这是一个用于查询的框架,有兴趣的朋友可以多加研究。
注:作为一个iOS开发者,其实如果可以的话你可以学会使用者三种方式,但是一般我们没有比较,除非你确实闲的蛋疼,
以后在公司中,我们一半都只会使用一种,所以作为一个合格的程序员,我们应该非常熟悉的使用其中的一种,这里比较推荐百度和苹果自带的,当你狠熟悉的使用这一种之后,另外两种学起来就很简单了,
当然,对于两外两种我们也应该有个大志的了解就可以,具体使用哪个看公司。
如果想要更深入的学习与研究请查看相应的官方实例代码和API