前言
现在基本APP的几乎都要使用地图功能,不过一般不是专门做地图类的APP不会研究太深,最近项目中使用到地图,个人是集成的高德地图的API,没去对比高德和百度地图的好坏,不过都说百度有点坑,我还是远离百度的好。
集成
高德的集成有CocoaPods集成和手动集成.
可以去高德开发平台,注册key,集成到项目中,文档很详细。
使用
这里主要讲我在项目中的功能,如图
主要思路,点击tableview的cell,将cell中的地址回调之前的界面中。
导入的文件
#import "MapViewController.h"
#import
#import
#import
#import "AMapTipAnnotation.h" //这是 高德2d地图demo中的私有文件
#define DefaultLocationTimeout 6 //定位超时时间
#define DefaultReGeocodeTimeout 3 //逆定理定位超时时间
interface声明和遵循的协议
@interface MapViewController ()
@property(nonatomic,strong)AMapSearchAPI *search ; //周边搜索类方法实例对象
@property(nonatomic,strong)MAMapView *mapView; //地图
@property(nonatomic,strong)CLLocation *currentLocation; //当前位置
@property(nonatomic,strong)NSMutableArray *dataArray; //存放名称 即cell的TextLabel 的text
@property(nonatomic,strong)NSMutableArray *subDataArray; //存放地址 即cell的detailTextLabel 的text
@property(nonatomic,strong)UITableView *tableview;
@property (nonatomic, strong) AMapLocationManager *locationManager;//地图管理单例类,初始化之前请设置 APIKey
@property (nonatomic, strong) UISearchController *searchController; //顶部搜索框
@property (nonatomic, copy) AMapLocatingCompletionBlock completionBlock; //逆定理定位回调
@end
基础配置和初始化. 懒加载基本配置不写了 search,tableview,dataArray,subDataArray
- (void)viewDidLoad {
[super viewDidLoad];
[self initMapViews];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back"
style:UIBarButtonItemStylePlain
target:self
action:@selector(returnAction)];//自定义返回
[self initSearchController];
[self.view addSubview:self.tableview];
[self initCompleteBlock];
[self configLocationManager];
}
#pragma 初始化
- (void)initSearchController
{
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; //初始化搜索框,nil表示在本视图控制器中展示
self.searchController.searchResultsUpdater = self; //UISearchResultsUpdating
self.searchController.dimsBackgroundDuringPresentation = NO; //搜索时,背景变暗色
self.searchController.hidesNavigationBarDuringPresentation = NO; //隐藏导航栏
self.searchController.searchBar.delegate = self; //UISearchBarDelegate
self.searchController.searchBar.placeholder = @"请输入关键字";
[self.searchController.searchBar sizeToFit]; //搜索框自适应
self.navigationItem.titleView = self.searchController.searchBar; // 将搜索框显示在导航栏标题视图处
}
- (void)initMapViews
{
_mapView = [[MAMapView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight/2)];
_mapView.compassOrigin = CGPointMake(_mapView.compassOrigin.x, 22); //指南针位置
_mapView.scaleOrigin= CGPointMake(_mapView.scaleOrigin.x, 22); //比例尺位置
_mapView.delegate =self; //MAMapViewDelegate
_mapView.desiredAccuracy = kCLLocationAccuracyBest; //设置定位精度
_mapView.showsCompass = NO; //是否显示指南针罗盘
_mapView.zoomLevel = 16.3; // 地图缩放等级
_mapView.zoomEnabled = YES; //是否支持缩放 默认yes
_mapView.userTrackingMode = MAUserTrackingModeFollow;//跟随用户移动
_mapView.showsUserLocation = YES;
_mapView.mapType = MAMapTypeStandard; //地图样式为普通地图。 还有卫星地图
_mapView.language = MAMapLanguageZhCN; //地图的语言
[self.view addSubview:_mapView];
}
- (void)initCompleteBlock //逆地理定位完成回调
{
__weak MapViewController *weakSelf = self;
self.completionBlock = ^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error)
{
if (error != nil && error.code == AMapLocationErrorLocateFailed)
{
//定位错误:此时location和regeocode没有返回值,不进行annotation的添加
NSLog(@"定位错误:{%ld - %@};", (long)error.code, error.localizedDescription);
return;
}
else if (error != nil
&& (error.code == AMapLocationErrorReGeocodeFailed
|| error.code == AMapLocationErrorTimeOut
|| error.code == AMapLocationErrorCannotFindHost
|| error.code == AMapLocationErrorBadURL
|| error.code == AMapLocationErrorNotConnectedToInternet
|| error.code == AMapLocationErrorCannotConnectToHost))
{
//逆地理错误:在带逆地理的单次定位中,逆地理过程可能发生错误,此时location有返回值,regeocode无返回值,进行annotation的添加
NSLog(@"逆地理错误:{%ld - %@};", (long)error.code, error.localizedDescription);
}
else
{
//没有错误:location有返回值,regeocode是否有返回值取决于是否进行逆地理操作,进行annotation的添加
}
//根据定位信息,添加annotation
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
[annotation setCoordinate:location.coordinate];
//有无逆地理信息,annotationView的标题显示的字段不一样
if (regeocode)
{
weakSelf.mapView.userLocation.title =regeocode.city;
weakSelf.mapView.userLocation.subtitle =regeocode.formattedAddress;
}
};
}
- (void)configLocationManager
{
self.locationManager = [[AMapLocationManager alloc] init];
[self.locationManager setDelegate:self];
//设置期望定位精度
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//设置定位超时时间
[self.locationManager setLocationTimeout:DefaultLocationTimeout];
//设置逆地理超时时间
[self.locationManager setReGeocodeTimeout:DefaultReGeocodeTimeout];
//设置不允许系统暂停定位
[self.locationManager setPausesLocationUpdatesAutomatically:NO];
//设置允许连续定位逆地理
[self.locationManager setLocatingWithReGeocode:YES];
[self.locationManager startUpdatingLocation]; //开始连续定位
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
[annotation setCoordinate:_currentLocation.coordinate];//设置标注
[self cleanUpAction]; //0.5s后关闭定位 ,开连续定位不开单次是因为发现高德开单次定位地图的定位速度很慢,而连续定位秒开启。
});
}
- (void)cleanUpAction
{
//停止定位
[self.locationManager stopUpdatingLocation];
[self.locationManager setDelegate:nil];
[self.mapView removeAnnotations:self.mapView.annotations]; //移除标注
}
点击标注,显示当前位置
- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view //选择定位的位置显示位置
{
if ([view.annotation isKindOfClass:[MAUserLocation class]]) {
[self initAction];
}
}
- (void)initAction
{
if (_currentLocation) {
AMapReGeocodeSearchRequest *requset = [[AMapReGeocodeSearchRequest alloc]init];
requset.location = [AMapGeoPoint locationWithLatitude:_currentLocation.coordinate.latitude longitude:_currentLocation.coordinate.longitude]; //经度和纬度
[self searchLocationWithCoordinate2D:_currentLocation.coordinate];
}
}
- (void)searchLocationWithCoordinate2D:(CLLocationCoordinate2D )coordinate {
//构造AMapReGeocodeSearchRequest对象
AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init];
regeo.location = [AMapGeoPoint locationWithLatitude:coordinate.latitude longitude:coordinate.longitude];
regeo.radius = 10000;
regeo.requireExtension = YES;
//发起逆地理编码
[self.locationManager requestLocationWithReGeocode:YES completionBlock:self.completionBlock];
}
长按切换标注,切换周边
- (void)mapView:(MAMapView *)mapView didLongPressedAtCoordinate:(CLLocationCoordinate2D)coordinate
{
[self searchReGeocodeWithCoordinate:coordinate];
}
- (void)searchReGeocodeWithCoordinate:(CLLocationCoordinate2D)coordinate
{
CLLocation *loca = [[CLLocation alloc]initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
_currentLocation = [loca copy];
[self clear];
[self.mapView setCenterCoordinate:coordinate animated:YES];
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
[annotation setCoordinate:coordinate];
[self.mapView addAnnotation:annotation];
[self.mapView selectAnnotation:annotation animated:YES];
[self searchAround];
}
搜索框搜索
#pragma 输入提示 搜索
- (void)searchTipsWithKey:(NSString *)key //搜索框搜索
{
if (key.length == 0) //长度为0不搜索
{
return;
}
AMapInputTipsSearchRequest *tips = [[AMapInputTipsSearchRequest alloc] init];
tips.keywords = key;
// tips.cityLimit = YES; 是否限制城市
[self.search AMapInputTipsSearch:tips]; //输入提示查询接口
}
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response //输入提示查询回调函数
{
if (response.count == 0) //如果没搜索到结果,则使用之前的数据显示tableview
{
return;
}
else{ // 如果有结果 ,现删除之前的所有数据
if (self.dataArray) {
[self.dataArray removeAllObjects];
[self.subDataArray removeAllObjects];
}
}
for (AMapTip *tip in response.tips) { //添加数据 ,最多50条
[self.dataArray addObject:tip.name];
[self.subDataArray addObject:tip.address];
if (_dataArray.count>=50) {
return;
}
}
[self clearAndShowAnnotationWithTip:response.tips.firstObject]; //清除标注,切换地图
[self.tableview reloadData];
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
[self searchTipsWithKey:searchController.searchBar.text];
if (searchController.isActive && searchController.searchBar.text.length > 0)
{
searchController.searchBar.placeholder = searchController.searchBar.text;
}
}
清除之前的标注 ,换上新的
- (void)clear
{
[self.mapView removeAnnotations:self.mapView.annotations];
if (self.mapView.overlays) {
[self.mapView removeOverlays:self.mapView.overlays];
}
}
- (void)clearAndShowAnnotationWithTip:(AMapTip *)tip
{
/* 清除annotations & overlays */
[self clear];
/* 可以直接在地图打点 */
AMapTipAnnotation *annotation = [[AMapTipAnnotation alloc] initWithMapTip:tip];
[self.mapView addAnnotation:annotation];
[self.mapView setCenterCoordinate:annotation.coordinate];
[self.mapView selectAnnotation:annotation animated:YES];
}
周边搜索
- (void)searchAround
{
AMapPOIAroundSearchRequest *Request = [[AMapPOIAroundSearchRequest alloc]init];
Request.location = [AMapGeoPoint locationWithLatitude:self.currentLocation.coordinate.latitude longitude:self.currentLocation.coordinate.longitude];
Request.types = @"道路附属设施|地名地址信息|公共设施|风景名胜|商务住宅|政府机构及社会团体";
// types属性表示限定搜索POI的类别,默认为:餐饮服务|商务住宅|生活服务
// POI的类型共分为20种大类别,分别为:
// 汽车服务|汽车销售|汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|
// 医疗保健服务|住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|
// 交通设施服务|金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施
// request.types = @"餐饮服务|生活服务";
Request.sortrule = 0; //排序 0 为距离排序
Request.requireExtension = YES;//是否返回扩展信息
[self.search AMapPOIAroundSearch: Request];
}
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response{
NSLog(@"周边搜索回调");
if(response.pois.count == 0)
{
return;
}
[self.dataArray removeAllObjects];
[self.subDataArray removeAllObjects];
NSArray *responseArray = [NSMutableArray arrayWithArray:response.pois];
// AMapPOI *poi = [[AMapPOI alloc]init];
for (AMapPOI *pod in responseArray) {
[self.dataArray addObject:pod.name]; //取搜索出来的名称
[self.subDataArray addObject:pod.address]; //取搜索出来的地址
if (_dataArray.count>=50) {
return;
}
}
// 周边搜索完成后,刷新tableview
[self.tableview reloadData];
}
。tableView的实现就不写了 。
结尾
为了让自己不忘记,以后忘记还能回来找找,也为了别人少点坑,毕竟我们只是一个小小的码农。。当然还有很多功能,官方文档一堆方法,有需求再找找。