UISearchController是iOS 8 之后推出的一个新的控件, 用于创建搜索条, 及管理搜索事件, 使用这个, 我们可以很容易的创建属于自己的搜索框。搜索框在app开发中是非常常见的,比如说我们要搜索一个地点。这里就利用到了这个控件,简单记录一下。
我们就以上面这个Demo举例实现一个简单的UISearchViewController的使用。
UISearchController 让用户在 UISearchBar 上输入搜索关键词,展示搜索结果或者进行其他操作。UISearchController 把两个控制器(UIViewController)连在一起。父控制器放置 UISearchBar 控件。当用户点击搜索框时,UISearchBar 会移到屏幕顶部;输入搜索关键词,UISearchBar 下面出现子控制器的view。
所以UISearchController是很少单独使用的,一般都是配合其他的控件进行使用,实现联想搜索结果的展示栏一般是使用UITableView实现的。
// 初始化方法, 参数是展示搜索结果的控制器, 如果是在当前控制器展示搜索结果, 就传nil
- (instancetype)initWithSearchResultsController:(nullable UIViewController *)searchResultsController;
// 负责更新搜索结果的代理, 需要遵循 UISearchResultsUpdating 协议
@property (nullable, nonatomic, weak) id <UISearchResultsUpdating> searchResultsUpdater;
// 搜索控制器是否是活跃状态, 当在一个控制器展示搜索结果的时候, 可以此来判断返回的数据源
@property (nonatomic, assign, getter = isActive) BOOL active;
// 控制器代理 遵循 UISearchControllerDelegate协议
@property (nullable, nonatomic, weak) id <UISearchControllerDelegate> delegate;
// 当搜索框激活时, 是否添加一个透明视图
@property (nonatomic, assign) BOOL dimsBackgroundDuringPresentation __TVOS_PROHIBITED;
@property (nonatomic, assign) BOOL obscuresBackgroundDuringPresentation NS_AVAILABLE_IOS(9_1); // default is YES
// 当搜索框激活时, 是否隐藏导航条
@property (nonatomic, assign) BOOL hidesNavigationBarDuringPresentation; // default is YES
@property (nullable, nonatomic, strong, readonly) UIViewController *searchResultsController;
@property (nonatomic, strong, readonly) UISearchBar *searchBar;
这里注意: UISearchController 在使用的时候, 需要设置为全局的变量或者控制器属性, 使其生命周期与控制器相同; 如果设置为局部变量, 会提前销毁, 导致无法使用.
这里的采用了高德的搜索SDK——高德开发手册
//
// SearchViewController.h
// ShareParking
//
// Created by 差不多先生 on 2022/3/26.
//
#import <UIKit/UIKit.h>
#import <AMapSearchKit/AMapSearchKit.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SearchViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, AMapSearchDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UISearchController *searchController;
// 数据源数组
@property (nonatomic, strong) NSMutableArray *datas;
// 搜索结果数组
@property (nonatomic, strong) NSMutableArray *results;
// 搜索接口
@property (nonatomic, strong) AMapSearchAPI* search;
@property (nonatomic, retain) MAUserLocation* currentLocation;
// 搜索字段
@property (nonatomic, strong) NSString* searchString;
@end
NS_ASSUME_NONNULL_END
首先我们要继承UISearchResultsUpdating协议。
这里因为我们默认搜索类型是停车场,所以初始化数据时,会自动检索当前位置附近的停车场。
以下是使用高德获取的数据。
(void)getParking {
_searchString = @"停车场";
_datas = [[NSMutableArray alloc] init];
self.search = [[AMapSearchAPI alloc] init];
self.search.delegate = self;
AMapPOIAroundSearchRequest *request = [[AMapPOIAroundSearchRequest alloc] init];
//当前位置
request.location = [AMapGeoPoint locationWithLatitude:34.15408339 longitude:108.90631727];
request.keywords = _searchString;
/* 按照距离排序. */
request.sortrule = 0;
request.requireExtension = YES;
// 启动任务
[self.search AMapPOIAroundSearch:request];
}
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response {
int j = 0;
if(response.pois.count == 0) {
NSLog(@"111");
return;
}
//通过 AMapPOISearchResponse 对象处理搜索结果
[self.datas removeAllObjects];
//解析response获取POI信息,具体解析见 Demo
for (AMapPOI *p in response.pois) {
j = 0;
for (int i = 0; i < _datas.count; i++) {
AMapPOI* a = _datas[i];
if ([p.name isEqual:a.name]) {
j = 1;
}
}
if (j == 0) {
//搜索结果存在数组
[self.datas addObject:p];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
// UI更新代码
[self.tableView reloadData];
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// 这里通过searchController的active属性来区分展示数据源是哪个
if (self.searchController.active) {
return self.results.count ;
}
return self.datas.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellID"];
}
if ([_datas[0] class] == [AMapPOI class]) {
AMapPOI *p = self.datas[indexPath.row];
cell.textLabel.text = p.name;
} else {
AMapTip* p = self.datas[indexPath.row];
cell.textLabel.text = p.name;
}
return cell;
}
这里我们需要将SearchBar加入tableView最上面的位置。
// 创建UISearchController, 这里使用当前控制器来展示结果
UISearchController *search = [[UISearchController alloc]initWithSearchResultsController:nil];
// 设置结果更新代理
search.searchResultsUpdater = self;
[self getParking];
// 因为在当前控制器展示结果, 所以不需要这个透明视图
search.dimsBackgroundDuringPresentation = NO;
self.searchController = search;
// 将searchBar赋值给tableView的tableHeaderView
search.searchBar.placeholder = @"选择停车位位置";
self.tableView.tableHeaderView = search.searchBar;
接下来我们需要调用协议方法:
这个方法会在我们输入时调用,我们可以在这里根据输入文字重新搜索位置,并且刷新tableView的数据。
// 输入响应函数
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
_searchString = searchController.searchBar.text;
[self inputAddress];
}
- (void)inputAddress {
AMapInputTipsSearchRequest *tips = [[AMapInputTipsSearchRequest alloc] init];
tips.keywords = _searchString;
tips.city = @"西安";
tips.cityLimit = YES;
[self.search AMapInputTipsSearch:tips];
}
/* 输入提示回调. */
- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response {
if(response.count == 0) {
NSLog(@"111");
return;
} else {
[_datas removeAllObjects];
for (int i = 0; i < response.count; i++) {
AMapTip* p = response.tips[i];
[_datas addObject:p];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
// UI更新代码
[self.tableView reloadData];
});
}
//@interface AMapTip : AMapSearchObject
/poi的id
//@property (nonatomic, copy) NSString *uid;
/名称
//@property (nonatomic, copy) NSString *name;
/区域编码
//@property (nonatomic, copy) NSString *adcode;
/所属区域
//@property (nonatomic, copy) NSString *district;
/地址
//@property (nonatomic, copy) NSString *address;
/位置
//@property (nonatomic, copy) AMapGeoPoint *location;
/类型码, since 4.5.0. 对应描述可下载参考官网文档 http://a.amap.com/lbs/static/zip/AMap_API_Table.zip。
//@property (nonatomic, copy) NSString *typecode;
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response {
int j = 0;
if(response.pois.count == 0) {
NSLog(@"111");
return;
}
//通过 AMapPOISearchResponse 对象处理搜索结果
[self.datas removeAllObjects];
//解析response获取POI信息,具体解析见 Demo
for (AMapPOI *p in response.pois) {
j = 0;
for (int i = 0; i < _datas.count; i++) {
AMapPOI* a = _datas[i];
if ([p.name isEqual:a.name]) {
j = 1;
}
}
if (j == 0) {
//搜索结果存在数组
[self.datas addObject:p];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
// UI更新代码
[self.tableView reloadData];
});
}