使用地图
iOS系统自带地图(主要是iPhone),为了使用地图,需要做如下步骤:
- 添加MapKit.framework;
- 添加Map View到对应界面;
- 设置Map View属性,例如:Type、Behavior等;
- 也可以在代码中进行设置,如:
- (void)viewDidLoad { [super viewDidLoad]; MKMapView *mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; [mapView setMapType: MKMapTypeHybrid]; [mapView setZoomEnabled:YES]; [mapView setScrollEnabled:YES]; [mapView setShowsUserLocation:YES]; [self.view addSubview:mapView]; }
- ok,可以看到地图展示的效果了。
GIS(Geographic Information System)介绍
我们需要了解几个方面的知识。
- GIS系统将地球分割为一个表格系统(这里的表格不是每个单元一样大的,甚至严格来说每个表格都不是一个矩形);
- 纬度的计算方式是从赤道到极点,北半球为正,南半球为负;
- 经度从格林尼治天文台分割,以东为正,以西为负;
- 坐标被标示为°,赤道上是360°,极点是0°;
- 一个map view是一个被平坦化的球面标识,一个地图上的点使用x和y来标识;
聚焦
下面使用一个小例子来看如何使用聚焦到某个地点的功能。我们在下面的步骤中都将采用拖拽方式生成界面的形式而不是手动编写界面生成代码。
- 工程添加framework;
- ViewController.h头文件中添加import <MapKit/MapKit.h>;
- 生成Map View的outlet变量;
- 接下来是将某个具体位置聚焦到地图中间的代码:
#import "ViewController.h" #import <MapKit/MapKit.h> // ShangHai #define SH_LATITUDE 31.14 #define SH_LONGITUDE 121.29 // BeiJing #define BJ_LATITUDE 39.55 #define BJ_LONGITUDE 116.24 // Span #define SPAN_VALUE 0.20f @interface ViewController () @end @implementation ViewController @synthesize mapView; - (void)viewDidLoad { [super viewDidLoad]; // region property: center, span MKCoordinateRegion region; CLLocationCoordinate2D center; center.latitude = BJ_LATITUDE; center.longitude = BJ_LONGITUDE; MKCoordinateSpan span; span.latitudeDelta = SPAN_VALUE; span.longitudeDelta = SPAN_VALUE; region.span = span; region.center = center; // assign region to map [mapView setRegion:region animated:YES]; }
代码中的span指的是在经度/纬度方面显示几个区域。换句话说,代表了一种比例尺的概念。span越大,越能显示更多的区域。 - 如果需要支持用户的位置,那么需要做的更多一些。首先需要做的是实现MKMapViewDelegate代理,ViewController.h头文件中需要设置:
#import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface ViewController : UIViewController <MKMapViewDelegate> @property (strong, nonatomic) IBOutlet MKMapView *mapView; @end
- 查看帮助,编写代理实现方法,这里主要在更新用户坐标时刷新,最终代码如下:
#import "ViewController.h" #import <MapKit/MapKit.h> @interface ViewController () @end @implementation ViewController @synthesize mapView; - (void)viewDidLoad { [super viewDidLoad]; [mapView setDelegate:self]; [mapView setShowsUserLocation:YES]; } - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { CLLocationCoordinate2D loc = [userLocation coordinate]; MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 500, 500); [self.mapView setRegion:region animated:YES]; }
- 运行在真机上即可查看结果。
添加注解
我们经常需要将某个地点标注到地图上,我们需要增加Annotation功能,实际就是一个标注。
- 我们创建一个MapAnnotation类,实现Annotation;
头文件:
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface MapAnnotation : NSObject <MKAnnotation> @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subTitle; - initWithPosition:(CLLocationCoordinate2D) coords; @end
.m文件:
#import "MapAnnotation.h" @implementation MapAnnotation @synthesize coordinate; @synthesize title; @synthesize subTitle; - initWithPosition:(CLLocationCoordinate2D) coords { if (self = [super init]) { self.coordinate = coords; } return self; } @end
- 然后使用上面创建的Annotation:
// ShangHai #define SH_LATITUDE 31.14 #define SH_LONGITUDE 121.29 // BeiJing #define BJ_LATITUDE 39.55 #define BJ_LONGITUDE 116.24 // Span #define SPAN_VALUE 0.20f @interface ViewController () @end @implementation ViewController @synthesize mapView; - (void)viewDidLoad { [super viewDidLoad]; // region property: center, span MKCoordinateRegion region; CLLocationCoordinate2D center; center.latitude = BJ_LATITUDE; center.longitude = BJ_LONGITUDE; MKCoordinateSpan span; span.latitudeDelta = SPAN_VALUE; span.longitudeDelta = SPAN_VALUE; region.span = span; region.center = center; // assign region to map [mapView setRegion:region animated:YES]; CLLocationCoordinate2D location; location.latitude = SH_LATITUDE; location.longitude = SH_LONGITUDE; MapAnnotation *anno = [[MapAnnotation alloc] initWithPosition: location]; [anno setTitle: @"Shanghai"]; [anno setSubTitle: @"Shanghai center"]; [mapView addAnnotation: anno]; }
- 完成,查看效果。
自定义注解
默认的注解是一个图钉一样的图标,点击后弹出文字。我们可以修改注解为我们期望的效果。
- 首先我们设置ViewController为MKMapViewDelegate代理;
- 在.m文件中设置代理为自身:
- (void)viewDidLoad { [super viewDidLoad]; [mapView setDelegate: self]; // region property: center, span MKCoordinateRegion region; CLLocationCoordinate2D center; center.latitude = SZ_LATITUDE; center.longitude = SZ_LONGITUDE; MKCoordinateSpan span; span.latitudeDelta = SPAN_VALUE; span.longitudeDelta = SPAN_VALUE; region.span = span; region.center = center; // assign region to map [mapView setRegion:region animated:YES]; CLLocationCoordinate2D location; location.latitude = SH_LATITUDE; location.longitude = SH_LONGITUDE; MapAnnotation *anno = [[MapAnnotation alloc] initWithPosition: location]; [anno setTitle: @"Shanghai"]; [anno setSubTitle: @"Shanghai center"]; [mapView addAnnotation: anno]; }
- 添加代理方法:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation { // view MKPinAnnotationView * view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"]; // pin color [view setPinColor:MKPinAnnotationColorPurple]; // enabled animated [view setEnabled: YES]; [view setAnimatesDrop: YES]; [view setCanShowCallout: YES]; // image button UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"customanno.png"]]; [view setLeftCalloutAccessoryView:imageView]; [view setRightCalloutAccessoryView: [UIButton buttonWithType: UIButtonTypeDetailDisclosure]]; return view; }
- 完成,查看效果。
增加AccessoryView点击效果
我们点击大头针会弹出自定义的AccessoryView,显示一个图文标题加上一个向右箭头,但是这些都是无法点击的,现在我们加上向右箭头点击效果。
我们添加一个代理方法:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation {
// view
MKPinAnnotationView * view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"];
// pin color
[view setPinColor:MKPinAnnotationColorPurple];
// enabled animated
[view setEnabled: YES];
[view setAnimatesDrop: YES];
[view setCanShowCallout: YES];
// image button
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"customanno.png"]];
[view setLeftCalloutAccessoryView:imageView];
[view setRightCalloutAccessoryView: [UIButton buttonWithType: UIButtonTypeDetailDisclosure]];
return view;
}
添加多个注解
我们可能希望将多个地点注解添加到我们的地图中,那么我们需要以下几步:
- 我们需要定义多个经纬度:
// ShangHai #define SH_LATITUDE 31.14 #define SH_LONGITUDE 121.29 // SuZhou #define SZ_LATITUDE 31.19 #define SZ_LONGITUDE 120.37 // ChangZhou #define CZ_LATITUDE 31.47 #define CZ_LONGITUDE 119.58 // KunShan #define KS_LATITUDE 31.23 #define KS_LONGITUDE 120.57 // Span #define SPAN_VALUE 2.0f
- 我们需要一个Annotation数组:
- (void)viewDidLoad { [super viewDidLoad]; [mapView setDelegate: self]; // region property: center, span MKCoordinateRegion region; CLLocationCoordinate2D center; center.latitude = KS_LATITUDE; center.longitude = KS_LONGITUDE; MKCoordinateSpan span; span.latitudeDelta = SPAN_VALUE; span.longitudeDelta = SPAN_VALUE; region.span = span; region.center = center; // assign region to map [mapView setRegion:region animated:YES]; NSMutableArray *annotations = [[NSMutableArray alloc] init]; MapAnnotation *anno; CLLocationCoordinate2D location; anno = [[MapAnnotation alloc] init]; location.latitude = SH_LATITUDE; location.longitude = SH_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"上海"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = SZ_LATITUDE; location.longitude = SZ_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"苏州"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = CZ_LATITUDE; location.longitude = CZ_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"常州"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = KS_LATITUDE; location.longitude = KS_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"昆山"]; [annotations addObject:anno]; [mapView addAnnotations:annotations]; }
- 我们需要修改代理方法,为了能够重用Annotation View,避免不必要的资源消耗,需要在创建view之前请求资源重用:
MKPinAnnotationView *view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"pin"]; if (view == nil) { view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"]; }
- 查看效果:
添加多个不同的注解
我们期望对不同的注解添加不同的显示效果,则需要添加如下代码:
- 对annotation添加属性,以便于能够识别不同属性数据:
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface MapAnnotation : NSObject <MKAnnotation> @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *subTitle; @property (nonatomic, copy) NSString *province; @property (nonatomic, copy) NSString *name; - initWithPosition:(CLLocationCoordinate2D) coords; @end
- 创建新类继承自MKPinAnnotationView,并且重写initWithAnnotation方法:
- (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]; // Get a referene to the annotation to get its state value MapAnnotation *myAnnotation = (MapAnnotation *)annotation; NSString *myImage; if ([myAnnotation.province isEqualToString:@"JiangSu"]) { myImage = @"jiangsu.png"; } else if ([myAnnotation.province isEqualToString:@"ShangHai"]) { myImage = @"shanghai.png"; } UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:myImage]]; self.leftCalloutAccessoryView = imageView; if ([myAnnotation.name isEqualToString:@"ShangHai"]) { self.image = [UIImage imageNamed:@"shanghai_anno.png"]; } self.enabled = YES; self.canShowCallout = YES; return self; }
- 在ViewController中初始化:
- (void)viewDidLoad { [super viewDidLoad]; [mapView setDelegate: self]; // region property: center, span MKCoordinateRegion region; CLLocationCoordinate2D center; center.latitude = KS_LATITUDE; center.longitude = KS_LONGITUDE; MKCoordinateSpan span; span.latitudeDelta = SPAN_VALUE; span.longitudeDelta = SPAN_VALUE; region.span = span; region.center = center; // assign region to map [mapView setRegion:region animated:YES]; NSMutableArray *annotations = [[NSMutableArray alloc] init]; MapAnnotation *anno; CLLocationCoordinate2D location; anno = [[MapAnnotation alloc] init]; location.latitude = SH_LATITUDE; location.longitude = SH_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"上海"]; [anno setName: @"ShangHai"]; [anno setProvince: @"ShangHai"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = SZ_LATITUDE; location.longitude = SZ_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"苏州"]; [anno setName: @"SuZhou"]; [anno setProvince: @"JiangSu"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = CZ_LATITUDE; location.longitude = CZ_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"常州"]; [anno setName: @"ChangZhou"]; [anno setProvince: @"JiangSu"]; [annotations addObject:anno]; anno = [[MapAnnotation alloc] init]; location.latitude = KS_LATITUDE; location.longitude = KS_LONGITUDE; [anno setCoordinate: location]; [anno setTitle: @"昆山"]; [anno setName: @"KunShan"]; [anno setProvince: @"JiangSu"]; [annotations addObject:anno]; [mapView addAnnotations:annotations]; }
- ViewController的viewForAnnotation方法变为:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation { // view MapAnnotationView *view = (MapAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"pin"]; if (view == nil) { view = [[MapAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"]; } return view; }
- 完成,查看效果。