这两天一直捣鼓着地图的选址功能,需要达到的要求是:1,能用户定位 2,大头针固定在地图中心,拖动地图停止后获取到该大头针的位置信息 3,能通过搜索框搜索到我们输入的地址
主要思路:大头针分为两个 一个是用户的位置大头针 另一个是所选取的位置的大头针(包括拖动后的大头针和搜索功能查找到位置的大头针,公用一个大头针 )并且两个大头针都成为控制器器属性。
我使用到的高德地图sdk是:
'AMap3DMap' , '5.2.1' #高德3D地图
'AMapSearch' , '5.2.1' #高德搜索功能
'AMapLocation', '2.4.0' #定位
完整代码如下:
#define Screen_Width [UIScreen mainScreen].bounds.size.width
#define Screen_Height [UIScreen mainScreen].bounds.size.height
@interface MapAddressViewController ()<MAMapViewDelegate, AMapSearchDelegate, UISearchBarDelegate, UISearchResultsUpdating, UITableViewDataSource, UITableViewDelegate, AMapLocationManagerDelegate>
///定位
@property (nonatomic, strong) AMapLocationManager *locationManager;
///定位按钮
@property(nonatomic,weak) UIButton *locationBtn;
///搜索 控制器
@property (nonatomic, strong) UISearchController *searchController;
///展示搜索结果tableView
@property (nonatomic, strong) UITableView *tableView;
///搜索提示 模型
@property (nonatomic, strong) NSMutableArray *tips;
///地图
@property (nonatomic, strong) MAMapView *mapView;
///大头针
@property (nonatomic, strong) MAPointAnnotation *pointAnnotation;
///大头针view视图
@property(nonatomic, strong) MAAnnotationView *annotationView;
///逆地理编码
@property (nonatomic, strong) AMapReGeocodeSearchRequest *regeo;
///逆地理编码使用的
@property (nonatomic, strong) AMapSearchAPI *search;
///单次定位的回调
@property (nonatomic, copy) AMapLocatingCompletionBlock completionBlock;
//显示地址的label
@property(nonatomic, weak) UILabel *addressL;
@end
@implementation MapAddressViewController
#pragma mark - 懒加载
- (AMapLocationManager *)locationManager {
if (!_locationManager) {
_locationManager = [[AMapLocationManager alloc]init];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
_locationManager.locationTimeout = 2;
_locationManager.reGeocodeTimeout = 2;
}
return _locationManager;
}
- (AMapReGeocodeSearchRequest *)regeo {
if (!_regeo) {
_regeo = [[AMapReGeocodeSearchRequest alloc]init];
_regeo.requireExtension = YES;
}
return _regeo;
}
- (MAPointAnnotation *)pointAnnotation {
if (!_pointAnnotation) {
_pointAnnotation = [[MAPointAnnotation alloc]init];
}
return _pointAnnotation;
}
- (AMapSearchAPI *)search {
if (!_search) {
_search = [[AMapSearchAPI alloc]init];
_search.delegate = self;
}
return _search;
}
#pragma mark - View周期
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.navigationBar.translucent = true;// ssslll
//初始化地图UI
[self setUpMap];
//初始化附加UI
[self setUpUI];
//初始化tableView
[self initTableView];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.searchController.active = NO;
}
#pragma mark - 初始化 / 方法调用
/**
添加地图背景
*/
- (void)setUpMap{
//在viewDidLoad里面添加背景和定位功能
//地图
self.mapView = [[MAMapView alloc]initWithFrame:CGRectMake(0, 0, Screen_Width, Screen_Height)];
[self.view addSubview:self.mapView];
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.mapView.userTrackingMode = MAUserTrackingModeFollow;
self.mapView.showsScale = NO;
//用户定位的点设置
MAUserLocationRepresentation *r = [[MAUserLocationRepresentation alloc] init];
r.showsAccuracyRing = NO;///精度圈是否显示,默认YES
// r.locationDotFillColor = [UIColor grayColor];///定位点蓝色圆点颜色,不设置默认蓝色
r.showsHeadingIndicator = YES;///是否显示方向指示(MAUserTrackingModeFollowWithHeading模式开启)。默认为YES
[self.mapView updateUserLocationRepresentation:r];
//初始化单次定位的回调 (要在定位之前先初始化)
[self initCompleteBlock];
//定位
[self.locationManager requestLocationWithReGeocode:YES completionBlock:self.completionBlock];
}
- (void)setUpUI{
/******************* 搜索框 ***********************/
UIView *searchV = [[UIView alloc] init];
searchV.backgroundColor = [UIColor whiteColor];
[self.view addSubview:searchV];
[searchV mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.offset(40);
make.left.right.offset(0);
make.top.offset(64);
}];
[searchV layoutIfNeeded];
self.tips = [NSMutableArray array];//poi搜索提示模型数组
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.searchController.searchBar.placeholder = @"请输入关键字";
[self.searchController.searchBar sizeToFit];
[searchV addSubview:self.searchController.searchBar];
self.searchController.searchBar.frame = searchV.bounds;
/******************* 定位点 ***********************/
UIButton *locationBtn = [[UIButton alloc] init];
self.locationBtn = locationBtn;
{
[locationBtn setImage:[UIImage imageNamed:@"locationBtn_n"] forState:UIControlStateNormal];
[locationBtn setImage:[UIImage imageNamed:@"locationBtn_h"] forState:UIControlStateHighlighted];
[self.view addSubview:locationBtn];
CGFloat space_bottom = 30;
CGFloat space_left = 0;
CGFloat locationBtnWH = 50;
[locationBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.view).offset(-(49 + space_bottom));
make.left.equalTo(self.view).offset(space_left);
make.width.height.equalTo(@(locationBtnWH));
}];
[locationBtn addTarget:self action:@selector(currentLoacation:) forControlEvents:UIControlEventTouchUpInside];
}
/******************* 地址显示 ***********************/
UIView *addressV = [[UIView alloc] init];
addressV.backgroundColor = [UIColor whiteColor];
[self.view addSubview:addressV];
[addressV mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.offset(52);
make.left.right.offset(0);
make.bottom.offset(-10);
}];
UILabel *addressL = [[UILabel alloc] init];
[addressV addSubview:addressL];
[addressL mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.bottom.top.offset(0);
make.left.offset(10);
}];
self.addressL = addressL;
}
/**
初始化定位回调
*/
- (void)initCompleteBlock{
__weak MapAddressViewController *weakSelf = self;
self.completionBlock = ^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error)
{
if (error) {
return ;
}
weakSelf.pointAnnotation.coordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
if (weakSelf.mapView.annotations.count < 2) {
[weakSelf.mapView addAnnotation:weakSelf.pointAnnotation];
}
[weakSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude) animated:YES];
//让地图在缩放过程中移到当前位置试图
[weakSelf.mapView setZoomLevel:15.1 animated:YES];
// MapAddressViewController *strongSelf = weakSelf;
// [strongSelf addAnnotationToMapView:weakSelf.pointAnnotation];
NSLog(@"%ld",weakSelf.mapView.annotations.count);
};
}
- (void)initTableView
{
// CGFloat tableY = CGRectGetMaxY(self.navigationController.navigationBar.frame);
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 44+44+20, self.view.frame.size.width, self.view.frame.size.height - 100) style:UITableViewStylePlain];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.hidden = YES;
[self.view addSubview:self.tableView];
}
/* 输入提示 搜索.*/
- (void)searchTipsWithKey:(NSString *)key
{
if (key.length == 0)
{
return;
}
AMapInputTipsSearchRequest *tips = [[AMapInputTipsSearchRequest alloc] init];
tips.keywords = key;
tips.city = @"厦门";
// tips.cityLimit = YES; 是否限制城市
[self.search AMapInputTipsSearch:tips];
}
- (void)clearAndShowAnnotationWithTip:(AMapTip *)tip
{
/* 清除annotations & overlays */
// [self clear]; // ---k
if (tip.uid != nil && tip.location != nil) /* 可以直接在地图打点 */
{
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(tip.location.latitude, tip.location.longitude);
[self.mapView setCenterCoordinate:location];
}
else if(tip.uid == nil && tip.location == nil)/* 品牌名,进行POI关键字搜索 */
{
AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init];
request.keywords = tip.name;
request.city = @"厦门";
request.requireExtension = YES;
[self.search AMapPOIKeywordsSearch:request];
}
}
#pragma mark - 点击事件
/**
点击回到 用户当前位置
*/
- (void)currentLoacation:(UIButton *)btn{
//定位
[self.locationManager requestLocationWithReGeocode:YES completionBlock:self.completionBlock];
}
#pragma mark - MAMapViewDelegate
/**
* @brief 根据anntation生成对应的View 自定义大头针代理
* @param mapView 地图View
* @param annotation 指定的标注
* @return 生成的标注View
*/
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
//用户位置的大头针
if ([annotation isKindOfClass:[MAUserLocation class]]) {
return nil;
}
//选取定位的大头针
if ([annotation isKindOfClass:[MAPointAnnotation class]]) {
static NSString *reuseIdetifier = @"annotationReuseIndetifier";
MAAnnotationView *annotationView = (MAAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdetifier];
if (annotationView == nil) {
annotationView = [[MAAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:reuseIdetifier];
}
//放一张大头针图片即可
annotationView.image = [UIImage imageNamed:@"personal_locate"];
annotationView.centerOffset = CGPointMake(0, -18);
self.annotationView = annotationView ; // ---k
return annotationView;
}
return nil;
}
/**
* @brief 地图将要发生移动时调用此接口
* @param mapView 地图view
* @param wasUserAction 标识是否是用户动作
*/
- (void)mapView:(MAMapView *)mapView mapWillMoveByUser:(BOOL)wasUserAction{
if (self.annotationView) {
[UIView animateWithDuration:0.15 animations:^{
self.annotationView.centerOffset = CGPointMake(0, -18 - 5);
}];
}
}
/**
滑动地图过程 代理
*/
- (void)mapViewRegionChanged:(MAMapView *)mapView {
self.pointAnnotation.coordinate = mapView.centerCoordinate;
}
/**
滑动地图结束 修改当前位置
*/
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
self.regeo.location = [AMapGeoPoint locationWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
[self.search AMapReGoecodeSearch:self.regeo];
if (self.annotationView) {
[UIView animateWithDuration:0.15 animations:^{
self.annotationView.centerOffset = CGPointMake(0, -18 + 5);
}];
}}
/**
滑动结束调用search的代理进行逆地理编码得到地理位置
*/
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response {
if (response.regeocode != nil) {
AMapReGeocode *reocode = response.regeocode;
//地图标注的点的位置信息全在reoceode里面了
NSLog(@"%@",reocode.formattedAddress);
AMapAddressComponent *address = reocode.addressComponent;//地址组成要素
AMapStreetNumber *streeNumber = address.streetNumber;//门牌信息
NSLog(@"%@---%@---%@---%@---(%@)",address.district,address.township,streeNumber.street,streeNumber.number,address.building);
self.addressL.text = [NSString stringWithFormat:@"%@%@%@%@",address.district,address.township,streeNumber.street,streeNumber.number];
}
}
#pragma mark - AMapSearchDelegate
/**
* @brief 输入提示查询回调函数
* @param request 发起的请求,具体字段参考 AMapInputTipsSearchRequest 。
* @param response 响应结果,具体字段参考 AMapInputTipsSearchResponse 。
*/
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response
{
if (response.count == 0)
{
return;
}
[self.tips setArray:response.tips];
// for (AMapTip in <#collection#>) {
// <#statements#>
// }
[self.tableView reloadData];
}
#pragma mark - UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
self.tableView.hidden = !searchController.isActive;
[self searchTipsWithKey:searchController.searchBar.text];
if (searchController.isActive && searchController.searchBar.text.length > 0)
{
searchController.searchBar.placeholder = searchController.searchBar.text;
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tips.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *tipCellIdentifier = @"tipCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tipCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:tipCellIdentifier];
cell.imageView.image = [UIImage imageNamed:@"locate"];
}
AMapTip *tip = self.tips[indexPath.row];
if (tip.location == nil)
{
cell.imageView.image = [UIImage imageNamed:@"search"];
}
cell.textLabel.text = tip.name;
cell.detailTextLabel.text = tip.address;
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AMapTip *tip = self.tips[indexPath.row];
NSLog(@"%@--%@---%@--- ",tip.name,tip.district,tip.address);
[self clearAndShowAnnotationWithTip:tip];
self.searchController.active = NO;
}
@end
上面获取到的信息是一个位置的具体信息,如果你想获取就近的POI信息 ,可以在地图结束拖动的代理做如下操作:
/**
滑动地图结束 修改当前位置
*/
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
// self.regeo.location = [AMapGeoPoint locationWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
AMapPOIAroundSearchRequest *r = [[AMapPOIAroundSearchRequest alloc] init];
r.location = [AMapGeoPoint locationWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
r.radius = 500; //查找半径 单位:米
r.sortrule = 0; // 排序: 0距离 1综合
// r.types = @"写字楼|公寓|建筑|餐饮"; //搜索的类型 多个用'|'分割
[self.search AMapPOIAroundSearch:r];
// [self.search AMapReGoecodeSearch:self.regeo];
if (self.annotationView) {
[UIView animateWithDuration:0.15 animations:^{
self.annotationView.centerOffset = CGPointMake(0, -18 + offsetY);
}];
}
}
然后在poi查找结果回调中获得数据:
/**
* @brief POI查询回调函数
* @param request 发起的请求,具体字段参考 AMapPOISearchBaseRequest 及其子类。
* @param response 响应结果,具体字段参考 AMapPOISearchResponse 。
*/
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response{
for (AMapAOI *poi in response.pois) {
NSLog(@"%@",poi.name);
}
}
提醒我自己: 1, 添加搜索栏的时候如果直接用Masonry添加约束, 刚进控制器那会儿还正常, 但是一点击搜索, 搜索栏就会跑到屏幕外(左上角屏幕之外)。解决办法是添加一个父控件,然后再将搜索栏用frame的形式添加到父控件。2,创建后的选取位置的大头针视图(是视图不是模型) 用属性保存起来 在地图即将拖动和拖动完成后的代理通过改变 centerOffset 来让大头针有动画效果(当然,也有其他方法可实现) 3,