更新搜索的内容
在UISearchControllerDelegate代理方法updateSearchResultsForSearchController中通过以下的代码来实现搜索的数据更新:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchText = searchController.searchBar.text;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SELF CONTAINS %@)", searchText];
filterArr = searchText.length>0?[dataArr filteredArrayUsingPredicate:predicate]:dataArr; //当搜索内容清空后也有内容
[self.tableView reloadData];
}
结果展示控制器问题
EOCSearchResultViewCtrl *resultSearchCtrl = [[EOCSearchResultViewCtrl alloc] init];
_searchCtrl = [[UISearchController alloc] initWithSearchResultsController:resultSearchCtrl];
在初始化UISearchController的时候initWithSearchResultsController如果设置为自己的话,设置成nil就好,不要设置成self,当设置为nil的时候也就是说搜索的结果,会在self中进行展示,当然一般是在self中用tableview进行展示。如果设置为别的控制器,就会展示在别的控制器中,其实也就只是相当于拆分开来罢了。
searchBar的问题
[self.view addSubview:self.tableView];
[self.tableView setTableHeaderView:self.searchCtrl.searchBar];
我们将searchBar设置为tableView的头视图,并且当点击搜索框的时候,在UISearchControllerDelegate代理的willPresentSearchController方法和didPresentSearchController方法分别打断点可得以下结果:
以上是打断点过后的图
以上是点击搜索框之前的图
以上是点击搜索框之后的图
从上可以知道当点击了searchBar过后,系统将searchBar取出来移到了导航栏上面,而不再是tableView的头视图,而且点击之前和之后的searchBar是同一个,查看他们的内存地址可以知道。
另外需要注意的点
- 当使用搜索框的时候最好不要将self.automaticallyAdjustsScrollViewInsets设置为NO,因为会很难调坐标,会出现64px的问题。
- searchBar添加在scrollView以及它的子类上,而不是添加在view上
- searchController必须设置成成员变量,否则只会是添加了一个view上去,而其代理方法那些都不会响应,因为你不设置成成员变量,出了那个方法,你就被释放掉了
-
definesPresentationContext 当SearchResultsController不为nil,即搜索结果在别的控制器展示的时候,需要将definesPresentationContext设置为YES,即表示当UISearchController控制器present到需要展示的目标控制器的时候,可以覆盖当前的控制器,否则当跳到目标控制器时,上面会有一段空白
修改搜索框的一些设置
//修改背景色
self.searchCtrl.searchBar.barTintColor = [UIColor yellowColor];
//修改光标和取消文字颜色
self.searchCtrl.searchBar.tintColor = [UIColor orangeColor];
//修改图标
[self.searchCtrl.searchBar setImage:[UIImage imageNamed:@"voice_gray"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
[self.searchCtrl.searchBar setImage:[UIImage imageNamed:@"message_gray"] forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal];
[self.searchCtrl.searchBar setImage:[UIImage imageNamed:@"message_gray"] forSearchBarIcon:UISearchBarIconClear state:UIControlStateHighlighted];
// KVC 修改textfield的文字
UITextField *textField = [self.searchCtrl.searchBar valueForKey:@"_searchField"];
textField.textColor = [UIColor orangeColor];
textField.font = [UIFont systemFontOfSize:12.f];
// KVC 修改textfield的默认提示文字 两级就用keyPath
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
// KVC 修改searchBar的取消按钮文字 两级就用keyPath
[self.searchCtrl.searchBar setValue:@"取消" forKey:@"_cancelButtonText"];
/* 下面是三期的内容 */
// 一、 修改searchBar 颜色,光标,cancel文字颜色
self.searchCtrl.searchBar.barTintColor = [UIColor redColor];
self.searchCtrl.searchBar.tintColor = [UIColor purpleColor]; // 修改光标,cancel文字颜色
// 二、 修改cancel文字
// 1. 必须cancelButton出现的时候,才可以修改,这样子不是我们想要的,体验效果差,使用的话,也要和_searchCtrl.searchBar.showsCancelButton = YES;结合使用
UIButton *cancelBtn = [self.searchCtrl.searchBar valueForKey:@"_cancelButton"];
[cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
// 2. 遍历找到button,它也会陷入和第一种方式一样的弊端:必须cancelButton出现的时候,才可以修改
// 3. 挺好的,推荐使用,但是需要注意,当你有navigationController的时候,你可能会全局修改UIBarButtonItem,通过这个方法:[[UIBarButtonItem appearance] setTitleTextAttributes,这样子导致bug
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitle:@"取消"];
// 三、 修改textField,变成半圆角;加一个边界
// 1. 第一种用kvc
UITextField *searchTextField = [self.searchCtrl.searchBar valueForKey:@"_searchField"];
searchTextField.layer.cornerRadius = 14.f;
searchTextField.layer.masksToBounds = YES;
searchTextField.layer.borderWidth = 2.f;
searchTextField.layer.borderColor = [UIColor brownColor].CGColor;
searchTextField.tintColor = [UIColor blackColor];
// 2. 第二种遍历
// 如果有上下两条边线就去掉上下两条边线,遍历就可以了
for (UIView *view in self.searchCtrl.searchBar.subviews) {
if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
[view removeFromSuperview];
}
}
上面是使用KVC来进行修改,也可以通过遍历的方法来进行修改,但是进行搜索过后,进入SearchResultsController后就回到了原状。
iOS11的改变
iOS11 搜索框做了很多改变,我们一般这么用:
if (@available(iOS 11, *)) {
self.navigationItem.searchController = self.searchCtrl;
self.navigationItem.hidesSearchBarWhenScrolling = NO;
[self.searchCtrl.searchBar setPositionAdjustment:UIOffsetMake(100, 0) forSearchBarIcon:UISearchBarIconSearch];
} else {
self.tabelView.tableHeaderView = self.searchCtrl.searchBar;
}
半定制搜索框
没有实现当点击搜索框的时候,会跳到导航条,但是可以改变textfield的大小,用系统的改变不了。自定义搜索框需要自定义UISearchController和UISearchBar。代码如下:
EOCClassSearchCtl:
#import
#import "EOCClassSearchBar.h"
@protocol EOCClassSearchCtrlDelegate
- (void)didStartSearching;
- (void)didTapSearchBtn;
- (void)didTapCancelBtn;
- (void)didChangeSearchText:(NSString *)text;
@end
@interface EOCClassSearchCtl : UISearchController
@property(nonatomic, strong)EOCClassSearchBar *classSearchBar;
@property(nonatomic, weak)id classSearchCtrlDelegate;
@end
#import "EOCClassSearchCtl.h"
@interface EOCClassSearchCtl ()
@end
@implementation EOCClassSearchCtl
- (instancetype)initWithSearchResultsController:(UIViewController *)searchResultsController {
if (self = [super initWithSearchResultsController:searchResultsController]) {
}
return self;
}
#pragma mark - UISearchBar delegate method
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
//代理传递方法
if (_classSearchCtrlDelegate) {
[searchBar becomeFirstResponder];
[_classSearchCtrlDelegate didStartSearching];
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
if (_classSearchCtrlDelegate) {
[searchBar resignFirstResponder];
[_classSearchCtrlDelegate didTapCancelBtn];
}
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (_classSearchCtrlDelegate) {
[_classSearchCtrlDelegate didChangeSearchText:searchText];
}
}
#pragma mark - getter method
- (EOCClassSearchBar *)classSearchBar {
if (!_classSearchBar) {
_classSearchBar = [[EOCClassSearchBar alloc] initWithFrame:CGRectMake(0.f, 0.f, self.view.eoc_width, 44.f)];
_classSearchBar.delegate = self;
}
return _classSearchBar;
}
@end
EOCClassSearchBar:
.h里面没有什么东西,.m文件如下:
#import "EOCClassSearchBar.h"
@interface EOCClassSearchBar ()
@property(nonatomic, strong)UITextField *searchTextField;
@property(nonatomic, strong)UIButton *cancelBtn;
@property(nonatomic, strong)UIImageView *searchBarImageView;
@end
@implementation EOCClassSearchBar
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 截取手势事件,避免当修改textfield的frame后,点击最左边的区域,也响应了事件
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
[self addGestureRecognizer:tapGesture];
}
return self;
}
- (void)tapAction
{
NSLog(@"%s", __func__);
}
//修改textfield的frame只能在layoutSubviews中
- (void)layoutSubviews {
[super layoutSubviews];
// 修改textfield的frame
self.searchTextField.frame = ({
CGRect frame = self.searchTextField.frame;
frame.origin.x = 60.f;
frame.size.width -= 60.f;
frame;
});
}
// 绘制搜索框
- (void)drawRect:(CGRect)rect {
self.barTintColor = [UIColor orangeColor];
self.tintColor = [UIColor redColor];
self.showsCancelButton = YES;
// self.barTintColor = EOCColor(240, 243, 245);
[self becomeFirstResponder];
UITextField *textField = self.searchTextField;
textField.placeholder = @"Search EightClock";
textField.font = [UIFont systemFontOfSize:12.f];
textField.backgroundColor = EOCColor(240, 243, 245);
textField.textColor = [UIColor greenColor];
textField.textAlignment = NSTextAlignmentLeft;
[self.cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
[self.cancelBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
//在搜索框的底部画一条绿线 画线条
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.f, self.frame.size.height)];
[path addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height)];
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.path = path.CGPath;
shapeLayer.strokeColor = [UIColor greenColor].CGColor;
shapeLayer.lineWidth = 2.5f;
[self.layer addSublayer:shapeLayer];
}
- (void)btnAction:(UIButton *)btn {
self.searchTextField.text = @"";
// 调用代理,清空搜索内容
[self.delegate searchBar:self textDidChange:@""];
}
#pragma mark - getter method
- (UITextField *)searchTextField {
if (!_searchTextField) {
for (id view in [[self.subviews lastObject ]subviews]) {
if ([view isKindOfClass:NSClassFromString(@"UISearchBarTextField")]) {
_searchTextField = (UITextField *)view;
}
}
}
return _searchTextField;
}
- (UIButton *)cancelBtn {
if (!_cancelBtn) {
for (id view in [[self.subviews lastObject ]subviews]) {
if ([view isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
_cancelBtn = (UIButton *)view;
}
}
}
return _cancelBtn;
}
- (UIImageView *)searchBarImageView {
if (!_searchBarImageView) {
for (id view in [[self.subviews lastObject ]subviews]) {
if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
_searchBarImageView = (UIImageView *)view;
// _searchBarImageView.userInteractionEnabled = YES;
}
}
}
return _searchBarImageView;
}
@end