项目需要实现仿微信朋友圈可定位、搜索附近位置的功能:
实现方法
第1步,集成SDK(这里使用 CocoaPods 安装)
pod 'AMapSearch' #地图SDK搜索功能
pod 'AMapLocation' #定位SDK
第2步,引入头文件
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <AMapLocationKit/AMapLocationKit.h>
#import <AMapSearchKit/AMapSearchKit.h>
第3步,配置Key
在调用定位时,需要添加Key,需要注意的是请在 SDK 任何类的初始化以及方法调用之前设置正确的 Key。
[AMapServices sharedServices].apiKey = @"b5a84655e2cef54d488e990287d26bb9";
第4步,更改info.plist
在info.plist的字段添加定位权限的申请,配置方式请参考手动部署部分说明。
第5步,配置后台定位
第6步,代码实现
#import "SearchSitesController.h"
@interface SearchSitesController () <UITextFieldDelegate,AMapLocationManagerDelegate,AMapSearchDelegate>
@property (nonatomic,strong) UITextField *searchTxt;//搜索框
@property (nonatomic,assign) BOOL isSearchAround;
@property (nonatomic,strong) NSMutableArray *addressArray;//搜索到的地址数组
@property (nonatomic,strong) AMapLocationManager *locationManager;//定位管理
@property (nonatomic,strong) AMapSearchAPI *searchAPI;//搜索类
@property (nonatomic,strong) CLLocation *location;//当前定位的位置
@property (nonatomic,copy) NSString *currentCity;//当前城市
@end
@implementation SearchSitesController
#pragma mark - 懒加载
- (NSMutableArray *)addressArray
{
if (!_addressArray) {
_addressArray = [NSMutableArray array];
}
return _addressArray;
}
- (AMapLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[AMapLocationManager alloc] init];
[_locationManager setDelegate:self];
[_locationManager setAllowsBackgroundLocationUpdates:YES];
//iOS 9(不包含iOS 9) 之前设置允许后台定位参数,保持不会被系统挂起
[_locationManager setPausesLocationUpdatesAutomatically:NO];
//iOS 9(包含iOS 9)之后新特性:将允许出现这种场景,同一app中多个locationmanager:一些只能在前台定位,另一些可在后台定位,并可随时禁止其后台定位。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
_locationManager.allowsBackgroundLocationUpdates = YES;
}
}
return _locationManager;
}
- (AMapSearchAPI *)searchAPI
{
if (!_searchAPI) {
_searchAPI = [[AMapSearchAPI alloc] init];
_searchAPI.delegate = self;
}
return _searchAPI;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStylePlain target:nil action:nil];
//搜索框
_searchTxt = [HELPER textFieldWithSuperView:self.view textAlignment:NSTextAlignmentLeft fontSize:14 textColor:TITLE_BLACK backgroundColor:RGB(243, 244, 246) placeholder:@"搜索地点" placeholderColor:PLACEHOLDER_COLOR placeholderFont:14 andMasonryBlock:^(MASConstraintMaker * _Nonnull make) {
make.left.equalTo(@11);
make.right.equalTo(@-55);
make.height.equalTo(@31);
make.top.equalTo(@(10));
}];
_searchTxt.delegate = self;
_searchTxt.layer.cornerRadius = 31/2;
_searchTxt.layer.masksToBounds = YES;
_searchTxt.clearButtonMode = UITextFieldViewModeWhileEditing;
_searchTxt.leftView = [[UIView alloc]initWithFrame:FRAME(0, 0, 35, 35)];
_searchTxt.leftViewMode = UITextFieldViewModeAlways;
[HELPER imageViewWithSuperView:_searchTxt.leftView backgroundColor:COLOR(clearColor) image:IMG(@"icon_search") andMasonryBlock:^(MASConstraintMaker * _Nonnull make) {
make.center.equalTo(self.searchTxt.leftView);
}];
[_searchTxt addTarget:self action:@selector(textFieldValueChanged:) forControlEvents:UIControlEventEditingChanged];
//取消按钮
[HELPER buttonWithSuperView:self.view andNormalTitle:@"取消" andNormalTextColor:PLACEHOLDER_COLOR andTextFont:16 andNormalImage:nil andCornerRadius:0 backgroundColor:COLOR(clearColor) addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside andMasonryBlock:^(MASConstraintMaker * _Nonnull make) {
make.centerY.equalTo(self.searchTxt.mas_centerY);
make.left.equalTo(self.searchTxt.mas_right).offset(5);
make.right.equalTo(@-5);
}];
//分割线
[HELPER imageViewWithSuperView:self.view backgroundColor:COLOR(groupTableViewBackgroundColor) image:nil andMasonryBlock:^(MASConstraintMaker * _Nonnull make) {
make.height.equalTo(@1);
make.left.right.equalTo(@0);
make.top.equalTo(self.searchTxt.mas_bottom).offset(10);
}];
//设置tableView
self.mainTableView = [self tableViewWithSuperView:self.view style:UITableViewStylePlain backgroundColor:COLOR(clearColor) target:self andMasonryBlock:^(MASConstraintMaker * _Nonnull make) {
make.left.right.bottom.equalTo(@0);
make.top.equalTo(self.searchTxt.mas_bottom).offset(11);
}];
self.mainTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.mainTableView.separatorColor = COLOR(groupTableViewBackgroundColor);
//开始定位
[self.locationManager startUpdatingLocation];
}
#pragma mark - 点击取消按钮
- (void)cancelAction:(UIButton *)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - AMapLocationManagerDelegate
/* 当定位发生错误时,会调用代理的此方法 */
- (void)amapLocationManager:(AMapLocationManager *)manager didFailWithError:(NSError *)error
{
//定位错误
LOG(@"定位❌error = %@",error);
}
/* 位置更新回调 */
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location
{
//经纬度
LOG(@"location:{lat:%f; lon:%f}", location.coordinate.latitude, location.coordinate.longitude);
self.location = location;
//逆地理编码
[self reGoecodeWithLocation:location];
//发起周边搜索
[self searchAroundWithKeywords:nil];
//停止定位
[self.locationManager stopUpdatingLocation];
}
//逆地理编码
- (void)reGoecodeWithLocation:(CLLocation *)location
{
AMapReGeocodeSearchRequest *request = [[AMapReGeocodeSearchRequest alloc] init];
request.location =[AMapGeoPoint locationWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude];
[self.searchAPI AMapReGoecodeSearch:request];
}
//根据定位坐标或关键字进行周边搜索
- (void)searchAroundWithKeywords:(NSString *)keywords{
if (keywords.length == 0) { //未输入关键字,则为POI周边搜索
self.isSearchAround = YES;
//构造AMapPOIAroundSearchRequest对象,设置周边搜索参数
AMapPOIAroundSearchRequest *request = [[AMapPOIAroundSearchRequest alloc] init];
request.location = [AMapGeoPoint locationWithLatitude:self.location.coordinate.latitude longitude:self.location.coordinate.longitude];
//types属性表示限定搜索POI的类别,默认为:餐饮服务|商务住宅|生活服务
//POI的类型共分为20种大类别
request.types = @"汽车服务|汽车销售|汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施";
request.sortrule = 0;
request.requireExtension = YES;
//发起周边搜索请求
[self.searchAPI AMapPOIAroundSearch:request];
}else{ //输入了关键字,则为搜索提示请求
self.isSearchAround = NO;
AMapInputTipsSearchRequest *tipsRequest = [[AMapInputTipsSearchRequest alloc] init];
tipsRequest.city = self.currentCity;//查询城市默认为当前定位的城市
tipsRequest.keywords = keywords;
[self.searchAPI AMapInputTipsSearch:tipsRequest];
}
}
#pragma mark - AMapSearchDelegate
/* 逆地理编码查询回调函数 */
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
self.currentCity = response.regeocode.addressComponent.city;
if (self.currentCity.length == 0) {
self.currentCity = response.regeocode.addressComponent.province;
}
LOG(@"当前定位城市 = %@",self.currentCity);
}
/* 实现POI搜索对应的回调函数 */
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response
{
[self.addressArray removeAllObjects];
if (response.pois.count>0) {
//将搜索出的POI结果保存到数组
[self.addressArray addObjectsFromArray:response.pois];
}else{
[self.mainTableView tableViewShowMessage:@"无结果" forDataCount:0];
}
[self.mainTableView reloadData];
}
/* 输入提示查询回调函数 */
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response
{
[self.addressArray removeAllObjects];
if (response.tips.count>0) {
//将搜索出的结果保存到数组
[self.addressArray addObjectsFromArray:response.tips];
}else{
[self.mainTableView tableViewShowMessage:@"无结果" forDataCount:0];
}
[self.mainTableView reloadData];
}
#pragma mark - <UITableViewDataSource,UITableViewDelegate>
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.addressArray.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
if (self.isSearchAround == YES) {//POI周边搜索
AMapPOI *poi = self.addressArray[indexPath.row];
cell.textLabel.text = poi.name;
cell.detailTextLabel.text = poi.address;
}else{//输入提示搜索
AMapTip *tip = self.addressArray[indexPath.row];
cell.textLabel.text = tip.name;
cell.detailTextLabel.text = tip.address;
}
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 50;
}
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 0.01;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 0.01;
}
-(UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return nil;
}
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
return nil;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - 监听textField值改变
- (void)textFieldValueChanged:(UITextField *)textField
{
[self searchAroundWithKeywords:textField.text];
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.view endEditing:YES];
return YES;
}
@end