项目中有需要检索功能的时候,就需要使用到
UISearchBar
,如果想做类似微信那种点击搜索框进入下一个页面,同时将搜索框迁移到Nabbar
上。可能你会想使用UISearchController
,可是使用的时候感觉要改的东西很多,能力有限,就自己来了。
示意图看一下:
首先是要确定UISearchBar 的布局,有几个方法,
1、打印子视图
2、看层级视图关系
3、拿到私有变量
打印子视图其实最好还是结合层级关系,
UISearchBar层级关系如下:
可以看到主要是由一个背景ImageView与UITextFild组成。
打印一下子视图如下:
for (UIView* subview in [_searchBar.subviews firstObject].subviews) {
NSLog(@"%@", subview.class);
}
2017-06-19 13:01:22.930 LXSearchBar[6314:170257] UISearchBarBackground
2017-06-19 13:01:22.931 LXSearchBar[6314:170257] UISearchBarTextField
通过debug 调试可以看清具体的类型:
说明 UISearchBarTextField 的类型是UITextFild类型
关于通过runtime拿到私有属性方法如下:
第一步:引入头文件:#import
第二步:方法:
1unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList([UISearchBar class], &outCount);
for (NSInteger i = 0; i < outCount; ++i) {
// 遍历取出该类成员变量
Ivar ivar = *(ivars + i);
NSLog(@"\n name = %s ======= type = %s", ivar_getName(ivar),ivar_getTypeEncoding(ivar));
}
// 根据内存管理原则释放指针
free(ivars);
清楚
UISearchBar
的层级关系后,我们可以通过遍历,去设置我们需要的改变的一些属性:
通过上面可以很清楚的知道,UISearchBar
是由一张背景图片和UITextField
组成的,所以已经很明确了。
如果要修改输入区域的颜色等等,可以通过设置UITextField
,如果设置背景图,可以设置一张颜色生成的图片作为背景。
for (UIView* subview in [_searchBar.subviews firstObject].subviews) {
NSLog(@"%@", subview.class);
// 打印出两个结果:
/*
UISearchBarBackground
UISearchBarTextField
*/
if ([subview isKindOfClass:[UITextField class]]) {
searchField = (UITextField*)subview;
// leftView就是放大镜
// searchField.leftView=nil;
// 删除searchBar输入框的背景
[searchField setBackground:nil];
[searchField setBorderStyle:UITextBorderStyleNone];
searchField.backgroundColor = self.searchAreaColor;
// 设置圆角
searchField.layer.cornerRadius = 15;
searchField.layer.masksToBounds = YES;
break;
}
if ([subview isKindOfClass:[NSClassFromString(@"UISearchBarBackground") class]]) {
UIImageView *backImageView = (UIImageView *)subview;
backImageView.image =[UIImage imageWithColor:[UIColor hexStringToColor:@"dddddd"] size:_searchBar.frame.size];
}
}
======插一个颜色生成图片的方法---
+(UIImage *)imageWithColor:(UIColor*)color size:(CGSize)size{
CGRect rect =CGRectMake(0,0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context =UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
通过上面我们已经修改了搜索区域的颜色已经背景图;
如果我们要修改UISearchBar
的取消按钮的文字或者颜色,就需要接下来的设置,网上看到可以通过上面的方法直接通过KVC
获取_cancelButton
,因为iOS
升级的原因,目前已经拿不到了,需要我们设置取消按钮显示时候可以拿到取消按钮,设置时机就是在即将开始编辑的时候设置显示
。
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
searchBar.showsCancelButton = YES;
// 然后设置searchBar的tint颜色
// [searchBar setBarTintColor:[UIColor whiteColor]];
for(id cc in [searchBar subviews]){
for (id subView in [cc subviews]) {
if ([subView isKindOfClass:[UITextField class]]) {
}else if([subView isKindOfClass:[UIButton class]]){
// 修改取消按钮
UIButton *btn = (UIButton *)subView;
[btn setTitle:self.cancelBtnName forState:UIControlStateNormal];
[btn setTitleColor:self.canceBtnColor forState:(UIControlStateNormal)];
}
}
}
return YES;
}
隐藏取消按钮的时机:
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
searchBar.showsCancelButton = NO;
[searchBar resignFirstResponder];
}
这样我们自定义UISearchBar就基本上完成了。
接下来继承与UISearchBar ,可是失败了。
新建类继承与UISearBar后,打印的层级关系如下:
for (UIView* subview in [_searchBar.subviews firstObject].subviews) {
NSLog(@"%@", subview.class);
}
2017-06-19 13:01:22.930 LXSearchBar[6314:170257] UISearchBarBackground
太操蛋了,只有一个背景图
所以放弃自定义UISearchBar。可以为了复用,可以写一个基类,暴露一个searchBar属性。
#import
@interface LXSearchController : UIViewController
@property(nonatomic,strong)UISearchBar *searchBar;
@end
#import "LXSearchController.h"
@interface LXSearchController ()
@property(nonatomic,strong)UIColor *searchAreaColor;//搜索区域的颜色
@property(nonatomic,copy)NSString *cancelBtnName;//取消按钮的名字
@property(nonatomic,strong)UIColor *canceBtnColor; //取消按钮的颜色
@property(nonatomic,strong)UIColor *backImageviewColor;//背景图的颜色
@property(nonatomic,assign)UIOffset mouseOffSet;//光标位置
@end
@implementation LXSearchController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationBar.translucent = NO;
self.navigationController.navigationBar.barTintColor = [UIColor hexStringToColor:@"#393d63"];
self.extendedLayoutIncludesOpaqueBars = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
self.view.backgroundColor =[UIColor whiteColor];
}
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
searchBar.showsCancelButton = YES;
// 然后设置searchBar的tint颜色
// [searchBar setBarTintColor:[UIColor whiteColor]];
for(id cc in [searchBar subviews]){
for (id subView in [cc subviews]) {
if ([subView isKindOfClass:[UITextField class]]) {
}else if([subView isKindOfClass:[UIButton class]]){
// 修改取消按钮
UIButton *btn = (UIButton *)subView;
[btn setTitle:self.cancelBtnName forState:UIControlStateNormal];
[btn setTitleColor:self.canceBtnColor forState:(UIControlStateNormal)];
}
}
}
return YES;
}
-(UISearchBar *)searchBar{
if (!_searchBar) {
_searchBar = [[UISearchBar alloc] initWithFrame:(CGRectMake(0, 64, Device_Width, 40))];
_searchBar.placeholder = @"姓名/昵称/电话";
_searchBar.delegate = self;
// 样式
_searchBar.tintColor = self.canceBtnColor;
_searchBar.searchBarStyle = UISearchBarStyleProminent;
// UISearchBar有一个searchTextPositionAdjustment属性就是设置光标偏移量的,类型为UIOffset结构体,赋值即可
//第一个值是水平偏移量,第二个是竖直方向的偏移量
_searchBar.searchTextPositionAdjustment = self.mouseOffSet;
// ** 自定义searchBar的样式 **
UITextField* searchField = nil;
// 注意searchBar的textField处于孙图层中
// _searchBar.backgroundColor = ;
for (UIView* subview in [_searchBar.subviews firstObject].subviews) {
NSLog(@"%@", subview.class);
// 打印出两个结果:
/*
UISearchBarBackground
UISearchBarTextField
*/
if ([subview isKindOfClass:[UITextField class]]) {
searchField = (UITextField*)subview;
// leftView就是放大镜
// searchField.leftView=nil;
// 删除searchBar输入框的背景
[searchField setBackground:nil];
[searchField setBorderStyle:UITextBorderStyleNone];
searchField.backgroundColor = self.searchAreaColor;
// 设置圆角
searchField.layer.cornerRadius = 15;
searchField.layer.masksToBounds = YES;
break;
}
if ([subview isKindOfClass:[NSClassFromString(@"UISearchBarBackground") class]]) {
UIImageView *backImageView = (UIImageView *)subview;
backImageView.image =[UIImage imageWithColor:[UIColor hexStringToColor:@"dddddd"] size:_searchBar.frame.size];
}
}
}
return _searchBar;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
self.searchBar.showsCancelButton = NO;
[ self.searchBar resignFirstResponder];
[self.view endEditing:YES];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
searchBar.showsCancelButton = NO;
[searchBar resignFirstResponder];
}
-(UIColor *)searchAreaColor{
if (!_searchAreaColor) {
_searchAreaColor =[UIColor hexStringToColor:@"F0EFF5"];
}
return _searchAreaColor;
}
-(NSString *)cancelBtnName{
if (!_cancelBtnName) {
_cancelBtnName = @"取消";
}
return _cancelBtnName;
}
-(UIColor *)canceBtnColor{
if (!_canceBtnColor) {
_canceBtnColor =[UIColor hexStringToColor:@"64c961"];
}
return _canceBtnColor;
}
-(UIColor *)backImageviewColor{
if (!_backImageviewColor) {
_backImageviewColor =[UIColor hexStringToColor:@"dddddd"];
}
return _backImageviewColor;
}
-(UIOffset)mouseOffSet{
UIOffset offset= UIOffsetMake(10, 0);
return offset;
}
@end
至于UISearchBar
添加到父视图的操作放在子类里进行。
新建一个类继承与刚才的基类:
@interface NextController : LXSearchController
@end
点击UISearchBar
就进入搜索结果页面,并且添加相应的过渡动画,UISearchBar放在NabBar下面:
#import "NextController.h"
#import "SearchResultController.h"
@interface NextController ()
@end
@implementation NextController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubview:self.searchBar];
}
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
SearchResultController *nextVc =[[SearchResultController alloc]init];
CATransition* transition = [CATransition animation];
transition.duration = 0.3;
transition.type = kCATransitionFade; //改变视图控制器出现的方式
transition.subtype = kCATransitionFromTop; //出现的位置
[self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
[self.navigationController pushViewController:nextVc animated:NO];
return YES;
}
搜索结果类进行同样的处理,继承与刚才的基类,返回按钮做一些处理,以及在加载UISearchBar的时候让UISearchBar就进入编辑状态 [self searchBarShouldBeginEditing:self.searchBar];
,并且把UISearBar设置为titleView:self.navigationItem.titleView = self.searchBar;
#import "SearchResultController.h"
@interface SearchResultController ()
@end
@implementation SearchResultController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIView *view =[UIView new];
self.navigationItem.leftBarButtonItem =[[UIBarButtonItem alloc]initWithCustomView:view];
[self searchBarShouldBeginEditing:self.searchBar];
[self.searchBar becomeFirstResponder];
self.navigationItem.titleView = self.searchBar;
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
searchBar.showsCancelButton = NO;
[searchBar resignFirstResponder];
[self.navigationController popViewControllerAnimated:NO];
}
示意图看一下:
demo地址:自定义UISearchBar