一、背景
想要做一个搜索功能,首先想到了系统的UISearchController
但是样式确需要高度的自定义。在适配的过程中发现了好多坑点,尤其是在iOS11上,现在将其总结到下面。
二、做法
修改searchBar的样式
// 1.设置placeholder
self.searchVC.searchBar.placeholder = @"Search music/author name.";
// 2.设置searchBar的背景透明
[self.searchVC.searchBar setBackgroundImage:[UIImage new]];
self.searchVC.searchBar.searchBarStyle = UISearchBarStyleMinimal;
// 3.设置搜索框文字的偏移
self.searchVC.searchBar.searchTextPositionAdjustment = UIOffsetMake(3, 0);
// 4.设置搜索框图标的偏移
CGFloat offsetX = (self.view.bounds.size.width - 200 - 32) / 2;
[self.searchVC.searchBar setPositionAdjustment:UIOffsetMake(offsetX, 0) forSearchBarIcon:UISearchBarIconSearch];
// 5.取消按钮和文本框光标颜色
self.searchVC.searchBar.tintColor = [UIColor blackColor];
// 6.设置搜索文本框背景图片 [圆形的文本框只需要设置一张圆角图片就可以了]
[self.searchVC.searchBar setSearchFieldBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor] size:CGSizeMake(self.view.bounds.size.width - 32, 36) isRound:YES] forState:UIControlStateNormal];
// 7.设置搜索按钮图片
UIImage *searchImg = [[UIImage imageNamed:@"cheez_search_icn"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[self.searchVC.searchBar setImage:searchImg forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
// 8.拿到搜索文本框
UITextField *searchField = [self.searchVC.searchBar valueForKey:@"_searchField"];
// 9.设置取消按钮文字
[self.searchVC.searchBar setValue:@"Custom Cancel" forKey:@"_cancelButtonText"];
如果设置了文字和按钮的偏移,需要在UISearchControllerDelegate
中在searchVC将要展示和消失的时候做文字按钮偏移处理[在将要展示searchVC的时候取消偏移,在searchVC将要消失的时候设置偏移]
#pragma mark - UISearchControllerDelegate
- (void)willPresentSearchController:(UISearchController *)searchController {
self.view.alpha = 1.0;
[searchController.searchBar setPositionAdjustment:UIOffsetMake(0, 0) forSearchBarIcon:UISearchBarIconSearch];
}
- (void)willDismissSearchController:(UISearchController *)searchController {
CGFloat offsetX = (self.view.bounds.size.width - 200 - 32) / 2;
[searchController.searchBar setPositionAdjustment:UIOffsetMake(offsetX, 0) forSearchBarIcon:UISearchBarIconSearch];
}
针对是否是iOS11版本的适配,注意如果在iOS11以下也建议把searchBar用一个view包起来然后添加到控制器中去,不然就有可能出现点击搜索框searchBar不见了等莫名其妙的情况:
// 2.Install the search bar
if ([self.navigationItem respondsToSelector:@selector(setSearchController:)]) {
// 2.1 For iOS 11 and later, wo place the search bar in the navigation bar
if (@available(iOS 11.0, *)) {
self.navigationItem.searchController = self.searchVC;
// 2.2 Set the search bar visible all the time
self.navigationItem.hidesSearchBarWhenScrolling = NO;
}
// 2.3 Hide line view
__weak typeof(self) weakSelf = self;
self.observerRef = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"kCFRunLoopBeforeWaiting");
BOOL targetView = [weakSelf barGroudView:weakSelf.navigationController.view];
if (targetView) {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
}
});
CFRunLoopAddObserver(CFRunLoopGetMain(), self.observerRef, kCFRunLoopDefaultMode);
} else {
UIView *v = [[UIView alloc] initWithFrame:self.searchVC.searchBar.bounds];
v.frame = CGRectMake(v.frame.origin.x, 64, v.frame.size.width, v.frame.size.height);
[v addSubview:self.searchVC.searchBar];
[self.view addSubview:v];
}
完整代码
- (void)prepareSearchVC {
WYMusicSearchResultVC *resultVC = [WYMusicSearchResultVC new];
self.searchVC = [[WYCustomSearchVC alloc] initWithSearchResultsController:resultVC];
[self.searchVC.view addSubview:resultVC.view];
// 1.Use resultVC to update the search results
self.searchVC.searchResultsUpdater = resultVC;
self.searchVC.searchBar.placeholder = @"Search music/author name.";
self.searchVC.searchBar.delegate = resultVC;
self.searchVC.delegate = resultVC;
[self.searchVC.searchBar setBackgroundImage:[UIImage new]];
self.searchVC.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchVC.searchBar.searchTextPositionAdjustment = UIOffsetMake(3, 0);
CGFloat offsetX = (self.view.bounds.size.width - 200 - 32) / 2;
[self.searchVC.searchBar setPositionAdjustment:UIOffsetMake(offsetX, 0) forSearchBarIcon:UISearchBarIconSearch];
self.searchVC.searchBar.tintColor = [UIColor blackColor]; // 取消按钮和文本框光标颜色
[self.searchVC.searchBar setSearchFieldBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor] size:CGSizeMake(self.view.bounds.size.width - 32, 36) isRound:YES] forState:UIControlStateNormal];
UIImage *searchImg = [[UIImage imageNamed:@"cheez_search_icn"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[self.searchVC.searchBar setImage:searchImg forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
[self.searchVC.searchBar sizeToFit];
// 2.Install the search bar
if ([self.navigationItem respondsToSelector:@selector(setSearchController:)]) {
// 2.1 For iOS 11 and later, wo place the search bar in the navigation bar
if (@available(iOS 11.0, *)) {
self.navigationItem.searchController = self.searchVC;
// 2.2 Set the search bar visible all the time
self.navigationItem.hidesSearchBarWhenScrolling = NO;
}
// 2.3 Hide line view
__weak typeof(self) weakSelf = self;
self.observerRef = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"kCFRunLoopBeforeWaiting");
BOOL targetView = [weakSelf barGroudView:weakSelf.navigationController.view];
if (targetView) {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
}
});
CFRunLoopAddObserver(CFRunLoopGetMain(), self.observerRef, kCFRunLoopDefaultMode);
} else {
UIView *v = [[UIView alloc] initWithFrame:self.searchVC.searchBar.bounds];
v.frame = CGRectMake(v.frame.origin.x, 64, v.frame.size.width, v.frame.size.height);
[v addSubview:self.searchVC.searchBar];
[self.view addSubview:v];
}
// 3.It is usually good to set the presentation context
self.definesPresentationContext = YES;
UITextField *searchField = [self.searchVC.searchBar valueForKey:@"_searchField"];
searchField.font = [UIFont systemFontOfSize:14];
}
- (BOOL)barGroudView:(UIView *)targetView {
for (UIView *sView in targetView.subviews) {
if ([sView isKindOfClass:NSClassFromString(@"_UINavigationControllerPaletteClippingView")]) {
if (sView.subviews.count > 0 && sView.subviews[0].subviews.count > 0 && sView.subviews[0].subviews[0].subviews.count > 1) {
sView.subviews[0].subviews[0].subviews[1].hidden = YES;
return YES;
}
}
}
return NO;
}
三、iOS11后UITbaleView刷新单行跳动解决方案
tableView.estimatedRowHeight = 0;
tableView.estimatedSectionFooterHeight = 0;
tableView.estimatedSectionHeaderHeight = 0;