iOS开发——高级技术&调用地图功能的实现

调用地图功能的实现

一:苹果自带地图

   学习如逆水行舟,不进则退。古人告诉我们要不断的反思和总结,日思则日精,月思则月精,年思则年精。只有不断的尝试和总结,才能让我们的工作和生活更加 轻松愉快和美好。连着做了两个大的商城外包项目,智慧城市,搜牧通,花费了近四个月的时间,终于在反复修改后完美收工。期间的困难自不必说,以后多多总结 和沟通吧。百度地图的使用之前已经发表了一篇文章,说的很详细了,这里不再涉及,言归正传,我们说一下如何调用苹果自带的地图iOS开发——高级技术&调用地图功能的实现

  第一步:导入地图文件  #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儿童手环。所以这里简单介绍定位与地图。

 

1 定位服务

    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 }

 

 

 

2 系统地图

    地图我目前用过系统、百度以及高德,开发人员使用都是差不多的,下面的代码涉及的类都是高德地图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

 

你可能感兴趣的:(ios开发)