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

本来觉得这个模块也就是一个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~~~~~~

时间: 2024-08-26 03:14:52

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

苹果Iphone手机通讯录、短信、微信、QQ聊天记录删除数据恢复+q:2100997525

百度官网认证QQ[百度唯一认证QQ:2100997525]专业破解苹果ID ,手机微信,手机号码监听,破译陌陌,QQ, 短信内容查询删除 开房登记记录 通话清单  QQ聊天记录查询删除 密码破解 邮箱以及各种聊天记录恢复与删除查询[百 度唯一认证QQ:2100997525]专业手机定位,通话清单,知己知彼,百战百胜,网站入侵等其他业务 ▌是您值得信赖的 怎么偷看別人的QQ聊天記錄?[百度唯一認証QQ:2100997525]專業破解苹果id.手机微信,破譯陌陌,QQ,郵箱以及各 種聊天記錄恢復與查

iOS开发 调用打电话,发短信

1.调用 自带mail[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://[email protected]"]]; 2.调用 电话phone[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8008808888"]];iOS应用内拨打电话结束后返回应用一般在应用中拨打电话的方

[android] 手机卫士接收短信指令执行相应操作

通过广播接收者,接收到短信,对短信内容进行判断,如果为我们指定的值就执行相应的操作 如果短信内容是”#*location*#” 就执行,获取手机位置 如果短信内容是”#*alarm*#” 就执行,播放报警音乐 如果短信内容是”#*wipedata*#” 就执行,远程清除数据 如果短信内容是”#*lockscrreen*#” 就执行,远程锁屏 把短信的优先级定义成1000 使用模拟器发送短息的时候,会自动给发送号码拼接上155xxxx等,判断时候会不准确,使用String对象的contains()

Android手机使用广播监听手机收到的短信

我们使用的Android手机在收到短信的时候会发出一条系统广播.该条广播中存放着接收到的短信的详细信息.本文将详细介绍如何通过动态注册广播来监听短信. 注册广播有两种方式,一种是动态注册,另一种是静态注册.动态注册,顾名思义就是在程序运行时注册的,需要用到广播的时候就注册,用完即销毁.静态注是在AndroidManifest.xml中注册的,在<application>中使用<receiver>标签注册. 那么如何创建一个监听短信的广播接收器呢,其实只需要新建一个类,让这个类继承B

html5开发手机打电话发短信功能,html5的高级开发,html5开发大全,html手机电话短信功能详解

在很多的手机网站上,有打电话和发短信的功能,对于这些功能是如何实现的呢.其实不难,今天我们就用html5来实现他们.简单的让你大开眼界. HTML5 很容易写,但创建网页时,您经常需要重复做同样的任务,如创建表单.在这...有 HTML5 启动模板.空白图片.打电话和发短信.自动完成等等,帮助你提高开发效率的同时,还带来了更炫的功能.好了,我们今天就来做一做看看效果吧!! 看代码: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitio

手机有新短信了,通过电脑提醒我

一般我使用手机的时间比较少,用电脑的时间比较多,手机轻度使用者,电脑就是重度了,上班或者下班回家后基本都是在用电脑,所以常常会有手机不在手边或者正在充电的情况,听歌正嗨着手机来电话或者来短信了基本很少会察觉到,来电话还好说短信就震动一回,等你去用手机的时候可能已经过了很久了,我想如果手机有短信来了能直接通过电脑告诉我不就好了,这样就不会错过,所以我想要手机有新短信了就在电脑上提醒我这么个功能. 接着查查有没有这类软件,发现有那么几个可以实现这个需求,但是功能有点多,是一个软件里面的其中一个功能.

SmsManager - Windows Phone手机PC端短信管理工具检查版本更新地址

SmsManager - Windows Phone手机PC端短信管理工具检查版本更新时将抓取此页面中两个特殊字符串之间的文字内容(共3处),并替换\n为换行,html转义字符为原字符. wpsmsmanager0-start[1.2]end-wpsmsmanager0 wpsmsmanager1-start[新版本V1.2已发布(2015/4/10)\n更新说明:\n可导出短信至Android手机\n前往查看?]end-wpsmsmanager1 wpsmsmanager2-start[htt

手机上的短信误删了还能恢复吗

手机上的短信误删了还能恢复吗?怎样找回手机中丢失的短信记录?随着经济的不断发展,手机的使用率越来越大,而更多用户使用的是安卓手机.我们通常会在手机中储存很多的短信信息,但是当短信很多的时候我们就需要对短信进行清理了,在清理的过程中我们有时候就会不小心清理掉手机中重要的短信,那么手机中重要的短信应该怎样找回呢,下面小编就来把找回短信记录的方法告诉大家.首先想要恢复手机里的短信记录,那么我们就需要做好充足的准备工作,我们需要使用到一款叫做极速数据恢复的恢复工具.先通过手机浏览器或者手机应用商店将它安

怎样恢复手机删除的短信内容

手机短信删除了怎么恢复?怎么最简单的恢复手机短信?误删的短信应该如何找回?最简单的找回方法这里来教你.不知道大家有没有在各种垃圾短信的删除时候,出现将重要的短信误删的情况.对于迷糊的小编就会经常的遇到这种情况.重要的短信误删了,真的会很麻烦,没有对应的短信一些操作就会无法进行.那么应该怎么办才能将误删的短信找回了,今天小编就和大家分享一种在手机上就可进行短信找回的方法,下面一起看一看吧.具体的操作步骤如下:第一步:在手机的软件管理市场,搜索并下载"极速数据恢复"软件,这款工具可以恢复手