标签:
本来觉得这个模块也就是一个SearchBar就搞定了,但是现在的产品经理也是够了,一会儿一个想法,之前的搜索
都已经写完了,类似主流的电商,好像也没那么麻烦,但是改版了总得弄点什么吧。嘿,哥们,我现在要iphone手机
通讯录里面搜索的样式,你搞定哦。。。。。。,要一毛一样哦。作为一个文化人,我只能在内心深处生
出表达出,苦逼的我们顶多发发牢骚,要改就改喽。
请看图先 这是他要的效果demo
下面是我写的demo
看到这效果,应该都能想到用UISearchController,但是这货是iOS8才出的,只能去找找老的UISearchDisplayController
简单分析下两个控件
1.UISearchDisplayController
Available in iOS 3.0
and later Deprecated in iOS 8.0 虽然被废弃了,但是如果需要支持7.0的话也只能勉强用用
其实他不是一个控制器,他只是一个继承于NSObject的一个工具类,你需要自己实例化一个UISearchBar的控件传给
这个类,而且他内部已经给封装好了一个UISearchResultTableView,用于在开始搜索的时候创建并展示搜索结果数据的。
A search display controller manages the display of a search bar, along with a table view that displays search
results.
2.UISearchController
Available in iOS 8.0 and later 每一个searchController都内置一个searchBar,用的时候就必须和你的MainUI关联起
来,例如你的基本UI是一个tableView,你可以把你的searchBar添加给tableHeaderView属性,那么搜索结果页面是
可以自定义的,可以自己设计一个controller,然后用这个方法initWithSearchResultsController:进行关联,当你的
searchbar被触发的时候,内部会自动调用你刚才关联的自定义搜索结果页面,代表要开始搜索了,那么这两者之间
就需要实现searchResultsUpdater
协议,可以让搜索栏通知到MainUI,就可以实时传参刷新搜索结果页面。
基本的初始化如下,由于我们主要介绍UISearchDisplayController,所以UISearchController简单带过了
下面是基本的初始化方法
// Create the search results controller and store a reference to it. MySearchResultsController* resultsController = [[MySearchResultsController alloc] init]; self.searchController = [[UISearchController alloc] initWithSearchResultsController:resultsController]; // Use the current view controller to update the search results. self.searchController.searchResultsUpdater = self; // Install the search bar as the table header. self.tableView.tableHeaderView = self.searchController.searchBar; // It is usually good to set the presentation context. self.definesPresentationContext = YES;
我感觉为什么UISearDisplayController被UISearchController替代了,从结构上来说,前者已经把搜索结果
页面给封装成了固定的UITableVIew了,这不坑爹了么,只能单纯的展示列表了,根本没有自定义空间,如果你要强制
修改他的属性,这更麻烦了,还要涉及到runtime,但是人家向下支持啊,没办法啊。UISearchController就先进了,
他内部封装好了UISearchBar,而且他的搜索结果页面是自定义的,只要实现代理方法就可以进行搜索了,这也符合现
在的开发逻辑,但是最低支持iOS 8.0啊。鱼和熊掌不可兼得啊,所以我暂时用了UISearchDisplayController给大家稍
微分析下逻辑。
Demo分析开始
第一步
各位看到上面的录屏,刚进来的界面是一个自己创建控制器,这里有两个方法,第一个你可以继承UITableVIewController,或者像我一样创建一个空的VC,然后自己添加一个TableVIew进去即可。那么自然需要几个属性来加载数据
@property (weak, nonatomic) IBOutlet UITableView *tableView; // 搜索界面上面展示热门搜索,下面展示历史搜索 @property (nonatomic,strong) NSMutableArray *hotDataSource; @property (nonatomic,strong) NSMutableArray *historyDateSource; // 搜索结果界面上面相关标签,下面展示相关文章 @property (nonatomic,strong) NSMutableArray *resultTagDataSource; @property (nonatomic,strong) NSMutableArray *resultArticleDataSource; @property (nonatomic,strong) UISearchBar *searchBar; @property (nonatomic,strong) UISearchDisplayController *displayController; // 搜索用的类先说下我如何加载数据进去,首先普通的主界面(搜索之前)他是一个TableView,分两个Section,这两个我都用collection做cell加载数据,那么搜索页面(搜索之后)他本身就是个内置的tableView,我也分两个Section,第一段用SKTagVIew来加载标签数据,需要标签布局流自适应的请看我写的另一个(传送门),第二段就是普通的cell了。
第二步
在需要的tableView里面注册对应的Cell
如何区分这两个tableView呢??
self.tableView 这个指的就是主界面的tableView
self.displayController.searchResultsTableView 这个就是搜索结果的tableView
我们只需要在实现的方法里面进行区分就好了
主页面在ViewDidload注册cell
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. // self.automaticallyAdjustsScrollViewInsets = NO; [self.tableView registerNib:[UINib nibWithNibName:identify1 bundle:nil] forCellReuseIdentifier:identify1]; [self.tableView registerNib:[UINib nibWithNibName:identify4 bundle:nil] forCellReuseIdentifier:identify4];
搜索结果页面在以下代理方法里面注册cell
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { NSLog(@"did load table"); [tableView registerNib:[UINib nibWithNibName:identify2 bundle:nil] forCellReuseIdentifier:identify2]; [tableView registerNib:[UINib nibWithNibName:identify3 bundle:nil] forCellReuseIdentifier:identify3]; [tableView registerNib:[UINib nibWithNibName:identify4 bundle:nil] forCellReuseIdentifier:identify4]; }
初始化UISearchBar以及相关的工具类
// 初始化UISearchBar self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 375, 44)]; // 设置placeholder [self.searchBar setPlaceholder:@"搜索"]; // 是否在编辑的时候需要cancel按钮 self.searchBar.showsCancelButton = NO; // 把键盘的returnkey换成search self.searchBar.returnKeyType = UIReturnKeySearch; // 设置代理 self.searchBar.delegate = self; self.searchBar.backgroundColor = [UIColor colorWithRed:246/255.0 green:246/255.0 blue:246/255.0 alpha:1]; self.searchBar.backgroundImage = [UIImage new]; // 把searchbar里面的textfield拿出来修改属性,原生的太丑了,黑黑的一片 UITextField *searchBarTextField = [self.searchBar valueForKey:@"_searchField"]; if (searchBarTextField) { [searchBarTextField setBackgroundColor:[UIColor whiteColor]]; [searchBarTextField setBorderStyle:UITextBorderStyleRoundedRect]; searchBarTextField.layer.cornerRadius = 5.0f; searchBarTextField.layer.borderColor = [UIColor colorWithRed:204/255.0 green:204/255.0 blue:204/255.0 alpha:1].CGColor; searchBarTextField.layer.borderWidth = 0.5f; } // 别忘了把设置好的Searchbar放到UItableVIew的头部去 self.tableView.tableHeaderView = self.searchBar; // 实例化控制器的类 UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self]; // 搜索类的代理 searchDisplayController.delegate = self; // 搜索类内部UItableVIew的代理 searchDisplayController.searchResultsDataSource = self; searchDisplayController.searchResultsDelegate = self; // [searchDisplayController setActive:YES animated:YES]; self.displayController = searchDisplayController;
实现TableView的代理方法,这里需要注意的是区分加载哪个Tableview,这里只是介绍如何加载不同的cell,其他代理
方法区分也是类似的
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (tableView == self.tableView) { HotTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identify1 forIndexPath:indexPath]; [self configCell:cell indexpath:indexPath tableView:tableView]; return cell; } else { NSString *identyfy = nil; if (indexPath.section == 0) { identyfy = identify2; } else { identyfy = identify3; } HotTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identyfy forIndexPath:indexPath]; [self configCell:cell indexpath:indexPath tableView:tableView]; return cell; } } - (void)configCell:(HotTableViewCell *)cell indexpath:(NSIndexPath *)indexpath tableView:(UITableView *)tableView { if (tableView == self.tableView) { if (indexpath.section == 0) { cell.dataLists = self.hotDataSource; cell.whichSection = 0; }else { cell.dataLists = self.historyDateSource; cell.whichSection = 1; } [cell.collectionView reloadData]; // CGRect rec = cell.collectionView.frame; // rec.size.width = [UIScreen mainScreen].bounds.size.width; // cell.collectionView.frame = rec; CGSize size = cell.collectionView.collectionViewLayout.collectionViewContentSize; cell.colletionViewHeight.constant = size.height; } else { // 第0段的时候是加载SKTagview if (indexpath.section == 0) { __weak typeof(self)weakSelf = self; [cell.tagListView removeAllTags]; cell.tagListView.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width; cell.tagListView.padding = UIEdgeInsetsMake(15, 10, 2, 10); cell.tagListView.interitemSpacing = 20; cell.tagListView.lineSpacing = 10; [self.resultTagDataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { SKTag *tag = [SKTag tagWithText:[NSString stringWithFormat:@"#%@",weakSelf.resultTagDataSource[idx]]]; // tag.padding = UIEdgeInsetsMake(3, 5, 3, 5); tag.font = [UIFont systemFontOfSize:13.0]; // tag.borderWidth = 0.5f; tag.bgColor = [UIColor whiteColor]; tag.cornerRadius = 3; // tag.borderColor = RGBA(191, 191, 191, 1); tag.textColor = [UIColor redColor]; tag.padding = UIEdgeInsetsMake(10, 5, 10, 5); tag.enable = YES; [cell.tagListView addTag:tag]; }]; cell.tagListView.didTapTagAtIndex = ^(NSUInteger index) { }; } else // 第1段就加载美女图片 { [cell.articleImage sd_setImageWithURL:[NSURL URLWithString:self.resultArticleDataSource[indexpath.row]] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { if (image && cacheType == SDImageCacheTypeNone) { cell.articleImage.alpha = 0; [UIView animateWithDuration:1.0 animations:^{ cell.articleImage.alpha = 1.0f; }]; } else { cell.articleImage.alpha = 1.0f; } }]; } } }
第五步
实现UISearchDisplayController的代理方法,这里我加了打印log以及注释,主要的方法里面一个是筛选本地数据进行
搜索,我这里是模拟的网络加载数据
#pragma mark UISearchDisplayDelegate //=============================================== - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller { NSLog(@"will begin search"); } - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { NSLog(@"did begin search"); } - (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { NSLog(@"will end search"); } - (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller { NSLog(@"did end search"); } - (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { NSLog(@"did load table"); [tableView registerNib:[UINib nibWithNibName:identify2 bundle:nil] forCellReuseIdentifier:identify2]; [tableView registerNib:[UINib nibWithNibName:identify3 bundle:nil] forCellReuseIdentifier:identify3]; [tableView registerNib:[UINib nibWithNibName:identify4 bundle:nil] forCellReuseIdentifier:identify4]; } - (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView { NSLog(@"will unload table"); } - (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView { NSLog(@"will show table"); } - (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView { NSLog(@"did show table"); } - (void)searchDisplayController:(UISearchDisplayController *)controller willHideSearchResultsTableView:(UITableView *)tableView { NSLog(@"will hide table"); } - (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView { NSLog(@"did hide table"); } - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { NSLog(@"should reload table for search string?"); // 如果是本地搜索就用下面的方法过滤,我这里用假数据模拟下网络加载 // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", searchString]; // self.searchResultDataSource = [[NSMutableArray alloc] initWithArray:[self.dataSource filteredArrayUsingPredicate:predicate]];; // self.resultVC.resultDataSource = self.searchResultDataSource; // [self.resultVC.tableView reloadData]; self.resultTagDataSource = [[NSMutableArray alloc] initWithArray:@[@"忠犬八公的故事",@"肖申克的救赎",@"致命魔术",@"致命ID",@"搏击俱乐部",@"绝命毒师",@"恐怖游轮",@"一只鸡",@"三只鸡",@"X男人",@"异次元骇客的呵呵呵呵呵呵呵呵"]]; self.resultArticleDataSource = [[NSMutableArray alloc] initWithArray:@[@"http://g1.ykimg.com/0130391F4555E1ADCCAB0C2BC11A026B822DCD-20CB-492B-E573-2C134BEAACD6", @"http://photo.880sy.com/4/2615/97666_small.jpg", @"http://android.tgbus.com/xiaomi/UploadFiles_8974/201204/20120419104740904.jpg", @"http://file.ynet.com/2/1507/26/10257216.jpg", @"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRJrreS_lZ4ha_qf4wuCBjvqqcNe_9mfGDvSpL6yW-s7Hw2acuwdA", @"http://images.china.cn/attachement/jpg/site1000/20160114/c03fd55670b218013ce02e.jpg", @"http://g2.ykimg.com/0130391F455393CD019187003FF99B6B5AD97A-861D-4127-04FC-F206FA63EF4D", @"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTWyinrltRMmvUI_o0cu3oaQO0mbGoRLR9qXqttq4kOO-Aox44MAg", @"http://i0.sinaimg.cn/edu/2015/0417/U1151P42DT20150417152321.jpg", @"http://news.xinhuanet.com/world/2010-02/26/124271_11n.jpg", @"https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSCXeL1x-x7y5Pk7qj4DlB_MGMHbY8DUuIgWR8mCLQIwRvCOyaO"]]; // 这里的returnYES代表数据回来立马刷新,但是如果是网络请求,咱们可以先给NO,然后再请求网络数据回来的异步方法里面进行一些刷新UI的操作 return YES; }
基本的介绍就OK了,由于我这里用到的都是IB实现的
需要细看Demo的朋友可以点击以下传送门:点击打开链接下载Demo
如果跑起来出现library not found for -lPods,说明链接不到cocoapods,各位自己重新pod install一下,版本不同
不会部分不能运行,问题不大,上面已经介绍很详细了,可以根本写个Demo试试
外国友人是如何修改内置TableView属性的介绍:点击打开链接
这里搜集了几个UISearchDisplayController的几点不足之处
3.不足之处 UISearchDisplayController从我使用过程中,感觉到有三点不足。 (1)使用UISearchDisplayController当键盘弹出来的时候,会默认把navagationBar给隐藏起来。如果不需要隐藏navagationBar,最好的处理方式就是重写UISearchDisplayController的-(void)setActive:(BOOL)visible animated:(BOOL)animated方法: 自定义一个类CustomSearchDisplayController,继承自UISearchDisplayController,然后在.m文件中重写该方法,并在该方法中主动显示navagationBar。 @implementation CustomDisplaySearchViewController - (void)setActive:(BOOL)visible animated:(BOOL)animated { [super setActive:visible animated:animated]; [self.searchContentsController.navigationController setNavigationBarHidden:NOanimated:NO]; } @end (2)UISearchDisplayController的tableView有一个标签,当没有匹配的结果时,默认会在tableView上显示一个“No Result”的标签。如果说想自定义这个标签,可以通过循环遍历出tableView上标签。 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { for (UIView* v in self.customDisplaySearch.searchResultsTableView.subviews) { if ([v isKindOfClass: [UILabel class]] && [[(UILabel*)v text] isEqualToString:@"No Results"]) { UILabel *label = (UILabel *)v; label.text = @"没有结果"; break; } } return YES; } (3)UISearchDisplayController的UISearchBar输入框当无输入时,SearchResultsTableView无法根据个人需求让表展示出来。我尝试过通过点击搜索栏delegate方法中去处理表展示问题,可是尝试失败了。
这个搜索控制器找了很多资料学习,确实对这两个控件有了个基本的了解,赶紧记录下
来,希望也能在一定程度上帮助学习的人,看到这里的人都是好人啊,博主带你飞
OVER~~~~~~
iOS之iPhone手机通讯录和短信搜索界面的实现以及UISearchController和UISearchDisplayController的浅析
标签:
原文地址:http://blog.csdn.net/deft_mkjing/article/details/51931625