[转载]IOS地图开发与定位
(2013-03-05 16:38:20)
原文地址:IOS地图开发与定位作者:哭吧晗
来源:http://blog.csdn.net/zhuiyi316/article/details/8306615
首先我们需要一个视图去呈现地图,苹果自带一个关于地图视图的类,名字叫MKMapView,可以在MapKit这个框架找到,所以用到地图需要在头文件中#import ,这样大家已经可以看到一个地图了,可以拖拽以及缩放。
下面是重点介绍如何去操作地图。
在这里我想介绍关于地图几个重要的属性和方法。
第一个属性:@property (nonatomic) MKMapType mapType;
这是一个结构体,有三个属性,决定地图的呈现风格。(在全房应用中没有用到,但我还是在这里提及一下)下面是关于这三个属性的介绍:
standard:标注地图,显示街道和街道名
Satellite:卫星图片区
Hybrid:卫星图,同时在相应区域有标注了街道和街道名
第二个属性:@property (nonatomic) MKCoordinateRegion region;
同样这也是一个结构体,看到名字应该想到这是一个标注视图上显示的地图区域。基本上一个区域是由中心点,和经度、纬度的跨越度决定的,这个跨越度也就是视图上的最大纬度或经度和最小纬度或经度之差。
typedef struct {
CLLocationCoordinate2D center;
MKCoordinateSpan span;
} MKCoordinateRegion;
给出这个结构体的定义应该会让大家明白很多。
这里大家可以直接去修改这个属性来改变地图在视图上的呈现区域,这样是不会产生动画效果的。如果要产生动画效果,大家可以用这个方法:
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
- 大家理解区域还有相关的只改变区域中心的方法可以自己看一下,在MKMapView.h的头文件中。
第三个属性:@property (nonatomic) BOOL showsUserLocation;
这个是用来决定是否显示用户位置,图中的蓝点是系统自带的用来显示用户位置。
这是几个常用的属性,下面介绍一下常用的一些方法:
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view;
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view;
- (CGRect)convertRegion:(MKCoordinateRegion)region toRectToView:(UIView *)view;
- (MKCoordinateRegion)convertRect:(CGRect)rect toRegionFromView:(UIView *)view;
这几个方法是进行视图区域和真实世界中的实际位置的转换,这个会经常用到。
介绍下面的方法前我想先解释一下“大头针”,以及它的用法
在用到地图的时候我们经常会向地图上加一些向上图那样的小视图,这些小视图都是MKAnnotationView的对象,我们称之为大头针吧。
还会有如上图的需求,也就是点击大头针会弹出一个视图,实际上它并不是视图,这个视图基本上是画上去的,会随着大头针的位置的改变而改变,也会随着信息的长度而自动伸缩,它的长度等是不能改变的,系统会很合适的改变它。
这些信息怎么放呢?我们需要自定义一个类,起名叫PinView吧。需要实现一个协议MKAnnotation;我简单的给一下头文件吧
@interface PinView : NSObject{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
它简单的包含了坐标,标题,以及副标题。标题也就是上图的:金狮温泉花园,副标题也就是上图的:在售:112套。
现在我们知道了如何去制定这些信息,可是却不知道怎么把大头针放上去,下面就要用到MKMapView的几个方法了:
- (void)addAnnotation:(id )annotation;
- (void)addAnnotations:(NSArray *)annotations;
- (void)removeAnnotation:(id )annotation;
- (void)removeAnnotations:(NSArray *)annotations;
第一个方法便是添加,可是这样还不够,大头针视图的呈现方式和风格是由我们来自己来决定的,这就用到了MKMapView的委托方法(既然是委托那么我们需要设置它的代理给合适的控制器):
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;
这个委托方法有两个参数,第一个是地图本身,第二个就是我们自定义的PinView对象。
还有一个返回值,就像是我们在用tableview的时候返回的cell是一样的,我们需要制订一个大头针返回,大家看一下下面的代码相信会很明白。
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id )annotation
{
static NSString *indentifer = @”QuanFangPinID”;//一个重用的标识往下看会明白的
MKPinAnnotationView *pinView = nil;
NSDictionary *tempDic;
if(annotation != mV.userLocation)//显示用户位置的那个蓝点也是大头针,我不希望改变它,所以在这里要判断一下
{
PinView *pin = (PinView *)annotation; //强制转换一下id类型的变量
pinView = (MKPinAnnotationView *)[mV dequeueReusableAnnotationViewWithIdentifier: indentifer];//熟悉吧,像不想tableview的重用机制,没错,地图也会重用大头针的
if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: indentifer] autorelease];//到这里一个空的MKPinAnnotationView对象基本初始化好了,可是如果仅是这样没有意义,我们要把它变成我们想的样子
for (UIView * view in [pinView subviews])
{
[view removeFromSuperview];
}
pinView.image = nil;//这是大头阵的样子,我们设为空,在后面会在大头针上添加自己定义的视图,当然你可以在这里定义自己的样子
pinView.canShowCallout = YES;//在点击大头针的时候会弹出那个黑框框,看看我上面发的图就知道了,这个就是决定能不能弹出的。
pinView.animatesDrop = NO;//地图在添加大头针时的会自带下落动画,这里可以决定用不用,如果不用,你可以自己定义其它的动画,下面我会介绍
pinView.draggable = NO;//这里决定pinView能不能拖动,应该经常会把它设为NO
UIImage *image = [UIImage imageNamed:@"45.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(-13, -1, 40.5, 48);
[pinView addSubview: imageView];
UILabel *labelTitle = [[UILabel alloc] initWithFrame:CGRectMake(-9, 0, 35, 30)];
labelTitle.backgroundColor = [UIColor clearColor];
labelTitle.font = [UIFont boldSystemFontOfSize:11];
labelTitle.textColor = [UIColor colorWithRed:62.0/255.0 green:26.0/255.0 blue:2.0/255.0 alpha:1.0];
labelTitle.textAlignment = UITextAlignmentCenter;
labelTitle.numberOfLines = 2;
if(![pin.title hasSuffix:@")"])
{
if(currentViewState == SecondHouseingDidAppear)
{
tempDic = [[secondHouseArr objectForKey:@"content"] objectAtIndex:pin.tag];//[self searchPinFromDic:secondHouseArr ForTitle:pin.title];
labelTitle.text = [NSString stringWithFormat:@"%.1fw",([[tempDic objectForKey:@"DIS_SALEPRICE"] floatValue]/10000)];
}
else if(currentViewState == SendHouseDidAppear)
{
tempDic = [[rentHouseArr objectForKey:@"content"] objectAtIndex:pin.tag];
labelTitle.text = [NSString stringWithFormat:@"%@",[tempDic objectForKey:@"DIS_RENTPRICE"]];
}
[pinView addSubview:labelTitle];
}
else {
tempDic = [mapShopArr objectAtIndex:pin.tag];
}
[labelTitle release];
[imageView release];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];;
rightButton.frame = CGRectMake(0, 0, 26, 26); rightButton.tag = pin.tag;
pinView.rightCalloutAccessoryView = rightButton;
}
return pinView;
}
下面还是一个委托方法,是在你的大头针都制定好了之后调到的,相应的,基本上是在上面这个委托方法执行成功后调用。
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views;
那么在这里你可以获取到所有你制定的大头针,这里你可以制订它们出现的动画,也就是上面我说的自定义动画。
其实它的委托与tableview的很相似,会在选择,取消选择的时候调用相应的委托,大家可以自己看一下MKMapView的头文件。其它的不太常用,我也没用到,敬请大家补充。
下面还是MKMapView的方法
- (void)selectAnnotation:(id )annotation animated:(BOOL)animated;
- (void)deselectAnnotation:(id )annotation animated:(BOOL)animated;
它的基本作用就是是否以动画的方式来自动选择大头针,效果就相当于我们点击或者取消点击一个大头针。
以上就是关于地图的一些基本操作,如果错误请指正,欢迎拍砖并且补充。
这里我还想介绍两样东西,与地图其实关系密切,
一个是谷歌的SVGeocoder
还一个是系统的定位管理
先说一下SVGeocoder,有这么几个方法
+ (SVGeocoder*)geocode:(NSString *)address completion:(void (^)(NSArray *placemarks, NSError *error))block;
+ (SVGeocoder*)geocode:(NSString *)address bounds:(MKCoordinateRegion)bounds completion:(void (^)(NSArray *placemarks, NSError *error))block;
+ (SVGeocoder*)geocode:(NSString *)address region:(NSString *)region completion:(void (^)(NSArray *placemarks, NSError *error))block;
+ (SVGeocoder*)reverseGeocode:(CLLocationCoordinate2D)coordinate completion:(void (^)(NSArray *placemarks, NSError *error))block;
基本上就是把经纬度和具体的地址信息互相转换。
下面介绍定位管理
需要导入#import
下面给一段创建定位管理的代码
CLLocationManager* locationManager_ = [[CLLocationManager alloc] init];//创建位置管理器
locationManager_.delegate=self;//设置代理
locationManager_.desiredAccuracy=kCLLocationAccuracyBest;//指定需要的精度级别
locationManager_.distanceFilter = 1000.0f;//设置距离筛选器
[locationManager_ startUpdatingLocation];//启动位置管理器
下面是两个委托方法,一个是在定位成功后的回调,一个是在失败后的回调,这是常用的。
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[manager stopUpdatingLocation];
[CostomUIKit mbpSuccess:@"定位失败"];
}
===========================下面方法在iOS6中已弃用=======
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
=============================================
上面方法在iOS6中的替代方法是:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
用一个数组来存储所有的位置信息,如果需要查看前一个位置信息,则利用[locations lastObject]可以返回原来的oldLocation。
提一下CLLocation,这是管理位置的类,最基本的是由经度和纬度组成的。
我们可以计算两个经纬度之间的距离通过下面这个方法:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location;
返回的是一个double类型的数据。