最近做大创,是开发高德地图的,从中学到点东西想和大家分享一下怎么在地图上创建一个自定义的大头针。
这个大头针的图像可以是从相册获取也可以拍照获取的(但是由于本人懒没有写裁剪照片的相关工具类所以用其他图片代替了,以后会更新添加这个功能)标题和描述都是用户自定义的
代码贴出来解析看注释
BuildSolidPageViewController.h文件
//引入相关的库
//UI相关的库
#import <UIKit/UIKit.h>
//用户位置管理的相关库
#import <CoreLocation/CoreLocation.h>
#import "ResultPageViewController.h"
@class BuildSolidPageViewController;
@interface BuildSolidPageViewController :UIViewController
@end
BuildSolidPageViewController.m文件
//
// BuildSolidPageViewController.m
// Bbian
//
// Created by dengwt on 2017/3/14.
// Copyright © 2017年 dengwt. All rights reserved.
//
#import "BuildSolidPageViewController.h"
//想要通过app获取照相功能和打开相册必须实现UINavigationControllerDelegate和UIImagePickerControllerDelegate代理
//想要获得当前地理位置必须实现CLLocationManagerDelegate并在代理方法中获取地理位置
@interface BuildSolidPageViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate,CLLocationManagerDelegate>
@property (strong,nonatomic)IBOutletUIImageView *image;
@property (strong,nonatomic)IBOutletUITextField *nameText;
@property (strong,nonatomic)IBOutletUITextField *describeText;
@property (strong,nonatomic)CLLocation* location;
@property (strong,nonatomic)CLLocationManager *locationManager;
@end
//界面在下面,做的比较简陋
@implementation BuildSolidPageViewController
- (void)viewDidLoad {
[superviewDidLoad];
self.navigationController.navigationBar.barTintColor = iCodeNavigationBarColor;
_locationManager=[[CLLocationManageralloc]init];
_locationManager.delegate=self;
//看看定位服务有没有打开,这里iOS8.0以上时要在info.list里面做响应的配置的
//在info.list里面添加Privacy - Location When In Use Usage Description即可
if (![CLLocationManagerlocationServicesEnabled]) {
NSLog(@"定位服务当前可能尚未打开,请设置打开!");
return;
}
//info.list里面配置的Privacy - Location When In Use Usage Description那么这里请求也应该对应。
if(![CLLocationManagerlocationServicesEnabled]||[CLLocationManagerauthorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
[_locationManagerrequestWhenInUseAuthorization];
//设置精度为最准确的
_locationManager.desiredAccuracy=kCLLocationAccuracyBest;
}
[_locationManagerstartUpdatingLocation];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//这个方法链接的是上图的拍照按钮,这里要注意的是BuildSolidPageViewController实现了相应的但是一定要记住将自己设置为UIImagePickerController等的代理!!
//否则相应的方法是不会被执行的,这就好比你请了个清洁工但不安排他干活一样
-(IBAction)takePhoto:(UIButton*)sender{
// 创建UIImagePickerController控制器对象
UIImagePickerController *picker = [[UIImagePickerControlleralloc]init];
picker.delegate =self;
picker.allowsEditing =YES;
picker.sourceType =UIImagePickerControllerSourceTypeCamera;
[selfpresentViewController:pickeranimated:YEScompletion:nil];
}
//这个是选取照片的的按钮相连的
-(IBAction)selectPhoto:(UIButton*)sender{
UIImagePickerController *picker = [[UIImagePickerControlleralloc]init];
picker.delegate =self;
picker.allowsEditing =YES;
picker.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;
[selfpresentViewController:pickeranimated:YEScompletion:nil];
}
//添加手势,点击空白出收起键盘
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[_nameTextresignFirstResponder];
[_describeTextresignFirstResponder];
}
//UIImagePickerControllerDelegate代理方法,选取完照片后执行
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
UIImage* chosenImage = info[UIImagePickerControllerEditedImage];
//让界面的UIImageView显示图像
self.image.image = chosenImage;
//看情况了,如果可以根据这个获取的话就用这个,不能就用定位了
//连取两次字典,可以取出里面经纬度和时间
// NSURL *referenceURL = [info objectForKey:UIImagePickerControllerReferenceURL];
// ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// [library assetForURL:referenceURL resultBlock:^(ALAsset *asset) {
// ALAssetRepresentation *rep = [asset defaultRepresentation];
// NSDictionary *metadata = rep.metadata;
//
// //NSLog(@"%@", metadata);
// NSDictionary *gps=[metadata objectForKey:@"GPS"];
// NSString *la=[gps objectForKey:@"Latitude"];
// NSString *lo=[gps objectForKey:@"Longitude"];
// if((la==nil)||(la.length==0)||(lo==nil)||(lo.length==0)){
// NSLog(@"经纬度获取失败");
// }
// double lat=la.doubleValue;
// double lon=lo.doubleValue;
// _location=[_location initWithLatitude:lat longitude:lon];
//
// } failureBlock:^(NSError *error) {
// // error handling
// }];
//一定要添加这段代码让用户选取完后能够回到原来的界面
[picker dismissViewControllerAnimated:YEScompletion:nil];
}
//用户取消选取后也是要让选取界面消失,让界面回到原来的界面
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissViewControllerAnimated:YEScompletion:nil];
}
//直接在这传值就好了
//应该来一个判断,如果是空值就做相应的处理
//将数据传到有MKMapView的界面展示大头针
-(IBAction)build{
if((_nameText!=nil)&&(_describeText!=nil)&&(_image!=nil)&&(_nameText.text.length!=0)&&(_describeText.text.length!=0)){
ResultPageViewController* result=[[ResultPageViewControlleralloc]init];
result.solidTitle=_nameText.text;
result.solidDescibe=_describeText.text;
result.solidImage=_image.image;
result._location=_location;
[self.navigationControllerpushViewController:resultanimated:YES];
}else{
[selfalertView];
}
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(@"出错了%@",error);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
//[_locationManager stopUpdatingLocation];
_location=[locationsfirstObject];
NSLog(@"地址是%@",_location);
//由于CLLocationManagerDelegate是苹果公司自家的,做的比较水,定位有很大的偏差到另一个界面经纬度就改为高德地图的了
[_locationManagerstopUpdatingLocation];
}
//相应的警告,当有相关信息是空的时候警告用户
- (void)alertView
{
UIAlertController *alertController = [UIAlertControlleralertControllerWithTitle:@"警告"message:@"照片和说明等不能为空"preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertActionactionWithTitle:@"取消"style:UIAlertActionStyleCancelhandler:^(UIAlertAction *_Nonnull action) {
NSLog(@"点击取消");
}]];
[alertController addAction:[UIAlertActionactionWithTitle:@"确定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *_Nonnull action) {
NSLog(@"点击确认");
}]];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
//选取完照片后添加描述大概就是这个样子了
//那么我们来看显示的界面是怎么样的,上代码
//
// ResultPageViewController.h
// Bbian
//
// Created by dengwt on 2017/3/14.
// Copyright © 2017年 dengwt. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "BuildSolidPageViewController.h"
#import <CoreLocation/CoreLocation.h>
//使用第三发所要引用的头文件,苹果都给我们封装好了
#import <MapKit/MapKit.h>
#import "KCAnnotation.h"
#import "SendtoServer.h"
@interface ResultPageViewController :UIViewController
//存储由上一个viewcontroller传过来的数据
@property(strong,nonatomic)NSString *solidTitle;
@property(strong,nonatomic)NSString *solidDescibe;
@property(strong,nonatomic)UIImage* solidImage;
@property CLLocation * _location;
//待会用高德的获取的经纬度算了,苹果坑死了
@property CLLocationCoordinate2D clocation;
@end
//
// ResultPageViewController.m
// Bbian
//
// Created by dengwt on 2017/3/14.
// Copyright © 2017年 dengwt. All rights reserved.
//
#import "ResultPageViewController.h"
//I don't know whether the UINavigationControllerDelegate is in neeed
//MKMapViewDelegate这个代理是要实现的,待会往地图添加大头针的时候要通过他来弄
@interface ResultPageViewController ()<UINavigationControllerDelegate,MKMapViewDelegate,CLLocationManagerDelegate>{
//这个可以不要的上面那个CLLocationManagerDelegate也可以不要的
CLLocationManager *_locationManager;
//真就是我们要展示大头针的地图了
MKMapView *_mapView;
}
@end
@implementation ResultPageViewController
@synthesize _location;
- (void)viewDidLoad {
[superviewDidLoad];
self.navigationController.navigationBar.barTintColor = iCodeNavigationBarColor;
[selfinitGUI];
//下面那个代码是发给服务器存储到数据库的,但是服务器还没做好
//[SendtoServer sendMessage:_solidImage title:_solidTitle describe:_solidDescibe url:@"URL" location:_location];
}
#pragma mark 添加地图控件
-(void)initGUI{
CGRect rect=[UIScreenmainScreen].bounds;
_mapView=[[MKMapViewalloc]initWithFrame:rect];
[self.viewaddSubview:_mapView];
//设置代理
_mapView.delegate=self;
//请求定位服务
_locationManager=[[CLLocationManageralloc]init];
if(![CLLocationManagerlocationServicesEnabled]||[CLLocationManagerauthorizationStatus]!=kCLAuthorizationStatusAuthorizedWhenInUse){
[_locationManagerrequestWhenInUseAuthorization];
[_locationManagerstartUpdatingLocation];
}
[_locationManagerstartUpdatingLocation];
//用户位置追踪(用户位置追踪用于标记用户当前位置,此时会调用定位服务)
_mapView.userTrackingMode=MKUserTrackingModeFollow;
//设置地图类型
_mapView.mapType=MKMapTypeStandard;
}
#pragma mark 添加大头针
-(void)addAnnotation{
//CLLocationCoordinate2D location1=_location.coordinate;
//CLLocationCoordinate2D location1=CLLocationCoordinate2DMake(43.81755895, 125.27000521);
KCAnnotation *annotation1=[[KCAnnotationalloc]init];
//设置标题
annotation1.title=_solidTitle;
//设置描述
annotation1.subtitle=_solidDescibe;
//设置经纬度
annotation1.coordinate=_clocation;
NSLog(@"到了这边地址是%@",_location);
//设置图片
annotation1.image=[UIImageimageNamed:@"barber_brush_filled-25.png"];
[_mapViewaddAnnotation:annotation1];
}
#pragma mark - 地图控件代理方法
#pragma mark 显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
//由于当前位置的标注也是一个大头针,所以此时需要判断,此代理方法返回nil使用默认大头针视图
if (annotation == mapView.userLocation){
NSLog(@"user看看谁先进来");
returnnil;
}
//添加大头针其实和tableview的用法类似
if ([annotationisKindOfClass:[KCAnnotationclass]]) {
NSLog(@"那就走着瞧");
staticNSString *key1=@"AnnotationKey1";
MKAnnotationView *annotationView=[_mapViewdequeueReusableAnnotationViewWithIdentifier:key1];
//如果缓存池中不存在则新建
if (!annotationView) {
annotationView=[[MKAnnotationViewalloc]initWithAnnotation:annotationreuseIdentifier:key1];
annotationView.canShowCallout=true;//允许交互点击
annotationView.calloutOffset=CGPointMake(0,1);//定义详情视图偏移量
annotationView.leftCalloutAccessoryView=[[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"apple_filled-25.png"]];//定义详情左侧视图
}
//修改大头针视图
//重新设置此类大头针视图的大头针模型(因为有可能是从缓存池中取出来的,位置是放到缓存池时的位置)
annotationView.annotation=annotation;
annotationView.image=((KCAnnotation *)annotation).image;//设置大头针视图的图片
return annotationView;
}else {
returnnil;
}
}
//一开始就会调用这段代码,用户位置更新的时候也会,可以在上面设置用户改变了多少米才更新
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
NSLog(@"%@",userLocation);
//设置地图显示范围(如果不进行区域设置会自动显示区域范围并指定当前用户位置为地图中心点)
// MKCoordinateSpan span=MKCoordinateSpanMake(0.01, 0.01);
// MKCoordinateRegion region=MKCoordinateRegionMake(userLocation.location.coordinate, span);
// [_mapView setRegion:region animated:true];
//这里是重点,让高德地图获取的经纬度的数据传到大头针上
_clocation=[userLocationcoordinate];
// if ((_clocation.longitude=0.0000000)||(_clocation.latitude=0.0000000)) {
// NSLog(@"经纬度再次获取失败");
// }
//等从高德里面获取经纬度才开始添加大头针
[selfaddAnnotation];
NSLog(@"%f and %f",_clocation.latitude,_clocation.longitude);
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end