自定义UISearchBar外观

作者: lexiaoyao20 | 来源:发表于2016-01-10 00:42 被阅读16714次

最近,在项目过程中遇到要自定义SearchBar的外观,虽然自己觉得用系统默认的外观就行了,不过UI设计师要求不用系统的默认样式,要跟app主题保持一致。

图1:设计效果图

从上图可以看出,我们要做的UISearchBar要有圆角,边框颜色,取消按钮颜色,背景透明等等。

开始以为可能要自己写一个自定义的UISearchBar控件了,后面研究了一番,发现可以设定系统UISearchBar属性来更改,便把经验记录下来跟大家分享一下。

首先,我们看下系统默认的SearchBar的样式,离我们的目标样式确实相差很大, 后面我会一步一步详细说明做成我们的目标样式。

图2:UISearchBar默认样式

1. 设置背景色

我以白色的背景色为例,下面看看代码:

//1. 设置背景颜色
    //设置背景图是为了去掉上下黑线
    self.customSearchBar.backgroundImage = [[UIImage alloc] init];
    // 设置SearchBar的颜色主题为白色
    self.customSearchBar.barTintColor = [UIColor whiteColor];
图3:设置SearchBar背景色为白色

2. 设置边框颜色和圆角

//2. 设置圆角和边框颜色
    UITextField *searchField = [self.customSearchBar valueForKey:@"searchField"];
    if (searchField) {
        [searchField setBackgroundColor:[UIColor whiteColor]];
        searchField.layer.cornerRadius = 14.0f;
        searchField.layer.borderColor = [UIColor colorWithRed:247/255.0 green:75/255.0 blue:31/255.0 alpha:1].CGColor;
        searchField.layer.borderWidth = 1;
        searchField.layer.masksToBounds = YES;
    }

这段代码有个特别的地方就是通过KVC获得到UISearchBar的私有变量
searchField(类型为UITextField),设置SearchBar的边框颜色和圆角实际上也就变成了设置searchField的边框颜色和圆角,你可以试试直接设置SearchBar.layer.borderColor和cornerRadius,会发现这样做是有问题的。

图4:设置边框颜色和圆角

嗯,离预期效果越来越近了!

3. 设置按钮(取消按钮)的文字和文字颜色

//3. 设置按钮文字和颜色
    [self.customSearchBar fm_setCancelButtonTitle:@"取消"];
    self.customSearchBar.tintColor = [UIColor colorWithRed:86/255.0 green:179/255.0 blue:11/255.0 alpha:1];
    //修正光标颜色
    [searchField setTintColor:[UIColor blackColor]];

//其中fm_setCancelButtonTitle是我写的UISearchBar一个分类的方法
- (void)fm_setCancelButtonTitle:(NSString *)title {
    if (IS_IOS9) {
        [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitle:title];
    }else {
        [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:title];
    }
}
图5:设置按钮文字和颜色

需要特别注意的是设置searchBar的tintColor会使输入框的光标颜色改变,可以通过设置searchField的tintColor来修正。

4. 设置输入框的文字颜色和字体

//4. 设置输入框文字颜色和字体
    [self.customSearchBar fm_setTextColor:[UIColor blackColor]];
    [self.customSearchBar fm_setTextFont:[UIFont systemFontOfSize:14]];

//下面两个方法是UISearchBar分类代码
- (void)fm_setTextColor:(UIColor *)textColor {
    if (IS_IOS9) {
        [UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]].textColor = textColor;
    }else {
        [[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:textColor];
    }
}

- (void)fm_setCancelButtonTitle:(NSString *)title {
    if (IS_IOS9) {
        [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitle:title];
    }else {
        [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:title];
    }
}
图6:最终对比效果图

5. 如何设置搜索图标

下面评论中有简友问我怎么更改默认的搜索图标,我查了下UISearchBar的API,发现有方法可以更改的。

//5. 设置搜索Icon
    [self.customSearchBar setImage:[UIImage imageNamed:@"Search_Icon"]
                  forSearchBarIcon:UISearchBarIconSearch
                             state:UIControlStateNormal];

为了跟系统默认Icon的有个明显的对比,我特殊找了张绿色的搜索Icon,效果见下图:

设置搜索Icon.png

Tips: 还可以设置其他的Icon(如清除按钮图标),也是用上面的方法,具体要设置什么,可以去看看UISearchBarIcon这个枚举。

2016-10-20新增

6.实现类似微信的搜索框

图8:提问.png

这里有位简友问到怎么实现类似微信的搜索框,下面我将详细说说我的思路。

首先,要告诉大家的是 UISearchBar 是一个由多个控件组合成的比较复杂的控件。用Reveal查看 UISearchBar 组成如下 :

图9:UISearchBar组成图.png

从上图可以看出UISearch的组成结构,下面我总结了一张思维导图,更加的清晰直观:

图10:UISearchBar思维导图.png

UISearchBar 的主要部分是 UISearchBarTextFieldUISearchBarTextField 又包含好几个subView,其中那个 UIButton 指的是清除按钮(输入文字时会出现)。

好了,上面说了一堆,其实我主要是想表达:既然 UISearchBar 是由这么多个子控件组成,我再往里面加一个按钮又何妨?

最终解决思路就是这样了:在 UISearchBarTextField 添加一个 UIButton,我暂且将它叫做 voiceButton,然后 voiceButton 设置好自动布局以及点击事件处理(点击按钮后,显示录音界面...),最后还要监控文本的变化,有输入了文本时,voiceButton 隐藏,没有文本时, 显示 voiceButton

所有代码如下:

//6. 实现类似微信的搜索框
    UIButton *voiceButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [voiceButton setImage:[UIImage imageNamed:@"Voice_button_icon"] forState:UIControlStateNormal];
    [voiceButton addTarget:self action:@selector(tapVoiceButton:) forControlEvents:UIControlEventTouchUpInside];
    [searchField addSubview:voiceButton];
    self.voiceButton = voiceButton;
    
    //Autolayout
    voiceButton.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *views = NSDictionaryOfVariableBindings(voiceButton);
    //设置水平方向约束
    [searchField addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[voiceButton(21)]-|" options:NSLayoutFormatAlignAllRight | NSLayoutFormatAlignAllLeft metrics:nil views:views]];
    //设置高度约束
    [searchField addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[voiceButton(21)]" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];
    //设置垂直方向居中约束
    [searchField addConstraint:[NSLayoutConstraint constraintWithItem:voiceButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:searchField attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];

//按钮触摸事件
- (IBAction)tapVoiceButton:(id)sender {
    NSLog(@"Tap voiceButton");
}

//监控文本变化
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    self.voiceButton.hidden = searchText.length > 0;
}

好了,打完收工,最终效果图如下:

record.gif

完整代码在这里

相关文章

网友评论

  • 想象纸中:我是用你的方法 设置圆角。效果一直不理想。给人的感觉就是 上下两条边似乎不能被“切割边缘”的感觉?请教你这个问题。
    想象纸中:好的。先谢谢楼主!
    lexiaoyao20:@想象之中3 http://hasjoh.cc/2017/12/11/%E5%AE%9A%E5%88%B6UISearchBar%E5%AF%BC%E8%88%AA%E6%A0%8F-%E5%90%8C%E6%AD%A5iOS-11/
    因为iOS11的SearchBar已经改了,你可以参考 一下这篇文章
  • 不泯iOS:你好,我想问一下,现在有什么办法可以谁让搜索栏上的搜索图标和文字居中呢
    lexiaoyao20:最近太忙了,一直没关注简书,也没时间更新博客,抱歉
    你看看这个是否满足你的要求:http://hasjoh.cc/2017/12/11/%E5%AE%9A%E5%88%B6UISearchBar%E5%AF%BC%E8%88%AA%E6%A0%8F-%E5%90%8C%E6%AD%A5iOS-11/
  • junfly:你好,感觉可以价格IB版,storyboard上怎么更改。这样效率更高。。
  • 小李童学:难道没有人发现吗,原设计图没有左边🔍吗,然而这样写一定会有🔍,亲
    lexiaoyao20:要隐藏也是可以的,参考:https://stackoverflow.com/questions/3245342/removing-the-image-on-the-left-of-an-uisearchbar/11647556
  • jade_xiaohui:非常棒。正好用上了。
    lexiaoyao20:@墓后煮屎人 很高兴能够帮到你~
  • TinXie:幫頂呀!
    最完善的 教學!
  • 清無:searchBar.backgroundImage = UIImage()
    if let tf = searchBar.value(forKey: "searchField") as? UITextField{
    tf.subviews[0].corner(radius: 14)
    }
    这样才完美
  • 清無:这个还比较详细点
  • 洁简:在iOS11上有点不一样了
  • Ko_Neko:请问下有办法设置搜索栏(放大镜所在View)的背景吗? 现在一直是白色 想变为灰色
    lexiaoyao20:你这样试试:

    UITextField *searchField = [self.customSearchBar valueForKey:@"searchField"];
    if (searchField) {
    [searchField setBackgroundColor:[UIColor grayColor]];
    }
  • 范小兵:什么代码编辑器😳
    范小兵:@落羽生 我说的是你那张UISearchBar组成图的左边的图看着是编辑器里面的吧?
    lexiaoyao20:用的 Markdown 语法
  • Highgray:当用拼音输入法时,按到第二个字母,再删除一个,右边清除按钮和声音的按钮就重叠了.这个问题怎么解决啊 老板
    Highgray:@落羽生 管用! 楼主v5
    lexiaoyao20:把监控文本变化的那个代理方法改成下面这个:
    - (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    self.voiceButton.hidden = searchBar.text.length + (text.length - range.length) > 0;
    return YES;
    }
  • CocoFei:我觉得自定义一个view,好像更简单吧!纯属感觉:blush:
  • 咔客:楼主 在吗? 用你的方法设置后 我想用键盘上面的搜索按钮作为事件响应 就会崩溃 类型就不对 有什么解决办法吗?
    lexiaoyao20:@咔客 发我qq邮箱吧:455295813@qq.com
    咔客:@落羽生 有邮件或者什么 我发下你
    lexiaoyao20:@咔客 有没有Demo可以看,光看你描述也没法知道问题所在
  • 一个努力的boy:这篇文章写的不错,对这个控件研究的很透彻
  • da4ab0a77bc6:自己写的程序是uisearchbar作为tableheaderview,求教怎么改变其中textfield与searchbar的边距
    lexiaoyao20:试试修改searchBar 的这个属性看看:searchTextPositionAdjustment,
    比如 self.searchBar.searchTextPositionAdjustment = UIOffsetMake(15, 0);
    表示在水平方向text离searchBar的距离为15个像素
  • beyourking:学习了 正在做搜索功能 :smile:
  • junfly:1024
  • b1a67a134e4d:在把voiceButton加在searchField中时,当searchField处于firstResponder时,貌似voiceButton不接收点击事件了.在把voiceButton加在customSearchBar中时就不影响接收点击事件,不知道是怎么回事,求大神指点
    lexiaoyao20:@zdbeyond 嗯嗯,不错
    b1a67a134e4d:多谢回复,可能不应该把button加在searchField中吧,加在searchBar中就可以接收点击事件,设置对应约束后在界面上看着跟加在searchField中一样一样的,嘿嘿
    lexiaoyao20:@zdbeyond 跟iOS事件响应链有关,searchField是第一响应者,在它内部点击,事件就没传递出去了,后续有时间再研究下怎么解决这个问题
  • 秋_明:特意滑到最下面来👍一个
    lexiaoyao20:@秋_明 受宠若惊:smiley:
  • 小魔仙儿:请问想在搜索栏添加个话筒按钮,当点击时候走语音功能。 跟微信一样 怎么搞呢?
    lexiaoyao20:@小魔仙儿 文章已更新,你看下第6节,另外,示例代码也已经更新:https://github.com/lexiaoyao20/CustomSearchBar
  • e4fa7826e618:用了设置icon位置,为什么还是无法把icon放到右边 求解答????
    e4fa7826e618:解决了亲
    lexiaoyao20:@businessios 你是怎么设置的?
  • 8cc60b1d01de:怎么去掉默认的图标图片呢,那个方法将图标为空也不想啊 :sweat:
    8cc60b1d01de:@豆花喵喵向前冲 也不行啊,打错了
  • 烟佛经:SearchBar.layer.borderColor和cornerRadius 会出什么问题啊
    lexiaoyao20:@烟佛经 外观会有问题,不是想要的效果
  • 583a28b22745:一直不知道怎么自定义,现在学习了
  • jane4321:很好,学习了。我还想问一个问题,怎么设置取消按钮的字体大小?
    jane4321:不错,已Star。 :grin:
    lexiaoyao20:@jane4321
    - (void)fm_setCancelButtonFont:(UIFont *)font {
    NSDictionary *textAttr = @{NSFontAttributeName : font};
    if (IS_IOS9) {
    [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitleTextAttributes:textAttr forState:UIControlStateNormal];
    }else {
    [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitleTextAttributes:textAttr forState:UIControlStateNormal];
    }
    }
    详细Demo可以看这里:https://github.com/lexiaoyao20/CustomSearchBar
    如果觉得不错记得给个Star哟 :smiley:
  • 穿山甲到底说了什么:问下楼主 ,为什么 当 searcBar 作为 self.navigationItem.titleView = searchBar的时候;
    [UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]].textColor = [UIColor redColor];
    [[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setFont:[UIFont systemFontOfSize:10]];都会失效,都会变成默认的黑色和默认字体,只有取消按钮title可以通过 [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitle:title];
    修改成功 正常我尝试了下将searchBar 包装在一个UIVIew *wrapView里面,还是没用,就是这样包装:
    UIView *wrapView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 375 - 2 * 44 - 2 * 15, 44)];
    [wrapView addSubview:self.customSearchBar];
    self.navigationItem.titleView = wrapView;
    最后 我猜测 估计是 哪里出现了问题,但是 用KVC直接取出 searchBar的searchField,然后设置
    searchField.textColor = [UIColor redColor];
    searchField.font = [UIFont systemFontOfSize:17];
    却能更改字体和颜色成功,一点问题都没有,!!我很费解,那个[UIAppearance xxx]这个类型调用机制 不给力啊,能 给个解释方向吗,感激不尽!


    lexiaoyao20:@穿山甲到底说了什么 我用下面的方法是可以的
    [[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:
    @{NSForegroundColorAttributeName:[UIColor redColor],
    NSFontAttributeName : [UIFont systemFontOfSize:25]}];

    我也没闹明白是为什么,我猜在NavigationBar上可能优先用DefaultTextAttributes效果吧。。
  • 33a02bf71691: self.customSearchBar.barTintColor = [UIColor blackcolor];背景色如果设置深颜色的就会变浅 毛玻璃效果? 有么有什么办法不让他变浅 而是真实的颜色呢
    lexiaoyao20:@重复昵称 能搞个Demo出来吗,我可以给你来调试一下
    33a02bf71691:@落羽生 还是不行 :sob:
    lexiaoyao20:@重复昵称
    你试下 self.customSearchBar.translucent = NO;
    如果还是不行,试试 self.customSearchBar.barStyle = UIBarStyleBlack;
    如果还不行,再告知我一声。。
  • 33a02bf71691:知道怎么改大小了 :relaxed:
    lexiaoyao20:@重复昵称 UIBarButtonItem的setTitleTextAttributes方法应该是可以设置字体大小的
  • 33a02bf71691:取消按钮的字体大小是不是不能改的
  • 33a02bf71691:真不错 :+1:
  • Rickie_Lambert: :+1: 楼主 真 棒, 对我 太有用了, 大赞 :+1: :+1: :+1: :+1: !!!
    lexiaoyao20:@Rickie_Lambert 很高兴能够帮到你:smile:
  • 陈鸡蛋:你好,知道怎么设置searchBar 的文字 左对齐吗? 默认是居中的 。找了好久没好到方法。。求助
    晓折:我也遇到了这个问题,现在的要求是,无论是不是第一响应者,提示文字都要一直靠左显示.我也试了很多方法了.
    lexiaoyao20:@Key_Chen 有一种方法就是去找产品经理谈,说服她用系统原生的效果就好了 :joy:
    lexiaoyao20:@Key_Chen 我试了很多种方法,貌似也不行。 searchBar.text = @"XXX",这样默认是左对齐的,你应该是要设置placeholder左对齐吧,UISearchBar对placeholder固定做了居中,实在不行的话,只能自己去写一个SearchBar了。
  • 我系哆啦:写的很详细,封装的也很好,看得出楼主写代码比较用心
    macfai:@落羽生 楼主真大神:+1::+1:
    lexiaoyao20:@我系哆啦 大家都能看懂的代码才是好代码:yum:
  • 程序H:请问为什么我点击取消没有效果呀
    lexiaoyao20:@人士浮屠 你需要实现UISearchBarDelegate代理方法:- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar; 具体你可以参考我文章最后发的那个Demo
  • 编号x71291:我想知道怎么改变searchBar的textfield的高度
    编号x71291:@落羽生 我也是暂时还没解决这个问题
    lexiaoyao20:@CatLoveDog 我今天试了下,貌似也没找到满意的解决方案。系统UISearchBar的高度是固定死的,如果真的要修改高度的话,可能要自己去重写了。 若你有好的解决方案,不妨告诉我一下。
    lexiaoyao20:@CatLoveDog 你看看这个对你有没有帮助:http://stackoverflow.com/questions/556814/changing-the-size-of-the-uisearchbar-textfield
    回头我在家里面再试一下~
  • 7babacee03ce: UITextField *searchField = [self.customSearchBar valueForKey:@"searchField"];
    调用KVC,有被拒的风险么?
    7babacee03ce:@落羽生 多谢 :smiley:
    lexiaoyao20:@ivars 没有的,具体原因可以参考这篇博客 http://blog.sunnyxx.com/2015/06/07/fullscreen-pop-gesture/ 里面的 关于私有API 那段
  • 再见远洋:多写点文章啊,期待你的干货
    再见远洋:@落羽生 嗯嗯,期待中
    lexiaoyao20:@再见远洋 多谢关注,一直想写,但是还没想到合适的主题。 这个周末尽量整一篇出来
  • flowerVV:非常感谢
  • dcdb9e0934f1:mark,很有用
    lexiaoyao20:@lalaluya :relieved:
  • 3d0eb8334cdd:能改变🔍这个图标么
    lexiaoyao20:@海底_捞月 这个是可以的

    //5. 设置搜索Icon
    [self.customSearchBar setImage:[UIImage imageNamed:@"Search_Icon"]
    forSearchBarIcon:UISearchBarIconSearch
    state:UIControlStateNormal];
  • 779b68e64744:写的很好,特别是用KVC获取私有属性,我经常这么干哈哈😄
  • 6605eae1686f:学习了
    lexiaoyao20:@征天紫龙 😋
  • 半尺尘:不错~
    lexiaoyao20:@半尺尘 谢谢关注:relaxed:

本文标题:自定义UISearchBar外观

本文链接:https://www.haomeiwen.com/subject/hdeahttx.html