iOS之iPhone手机通讯录和短信搜索界面的实现以及UISearchController和UISearchDisplayController的浅析

请看图先 这是要的效果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一下,由于

cocoapods版本不同(1.0上下还是有区别的,需要包个Target 和 end作为外层)会部分不能运行

,不过问题不大,上面已经介绍很详细了,可以根本写个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方法中去处理表展示问题,可是尝试失败了。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值