美文网首页iOS Developer
ios 当遇到继承与UISearchBar失败后

ios 当遇到继承与UISearchBar失败后

作者: 雪_晟 | 来源:发表于2017-06-19 13:46 被阅读118次

    项目中有需要检索功能的时候,就需要使用到UISearchBar,如果想做类似微信那种点击搜索框进入下一个页面,同时将搜索框迁移到Nabbar上。可能你会想使用UISearchController,可是使用的时候感觉要改的东西很多,能力有限,就自己来了。

    示意图看一下:


    SearchBar.gif

    首先是要确定UISearchBar 的布局,有几个方法,
    1、打印子视图
    2、看层级视图关系
    3、拿到私有变量

    打印子视图其实最好还是结合层级关系,

    UISearchBar层级关系如下:


    层级.png

    可以看到主要是由一个背景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 调试可以看清具体的类型:


    层级2.png
    说明 UISearchBarTextField 的类型是UITextFild类型
    关于通过runtime拿到私有属性方法如下:

    第一步:引入头文件:#import <objc/runtime.h>
    第二步:方法:

    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 <UIKit/UIKit.h>
    
    @interface LXSearchController : UIViewController<UISearchBarDelegate>
    
    @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];
    }
    
    

    示意图看一下:


    SearchBar.gif

    demo地址:自定义UISearchBar

    相关文章

      网友评论

        本文标题:ios 当遇到继承与UISearchBar失败后

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