iOS- 一种自定义NavigationBar的方式

NavigationBar这个最基本的控件想必大家都接触的不少,更是有各种各样的自定义的方式。我这边也分享一种根据项目需求而构想的自定义NavigationBar,可能并不是很通用,权当参考。

先看下项目界面简图:

iOS- 一种自定义NavigationBar的方式_第1张图片
界面.png

Bar左边三个控件,返回按钮,logo图片,当前页面的title相对来说是固定的,除了最基础的几个Tab页面不需要返回按钮,每个页面都有这三个控件。
Bar右边是不同的功能按钮,数量0-3个不等。

接下来具体实现。
采用UIView来模拟NavigationBar,所以在NavigationController中先隐藏navigaitonBar

self.navigationBar.hidden = YES;

然后将自定义的navigationBar(下称CustomNaviBar)添加到NavigationController中。

CustomNaviBar初始创建时只添加logo imageView和title Label这两个控件。

CustomNaviBar提供如下几个方法:

/**
更新当前页面title
页面初始化时调用 (建议viewDidAppear)
*/
- (void)updateNaviBarTitle:(NSSring *)title;

更新title方法实现即给Label赋值,设置布局,这里提一个小点,为了某些页面title是灵活配置的布局正常,传入的title去除收尾空格。

self.titleLabel.text = [title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

/**
 添加返回按钮
 push到下一个页面时,在NavigationController中调用
*/
- (void)remakeSubViewsForBackBtn;

这个方法顾名思义,添加返回按钮。方法的实现也仅仅是添加按钮,调整控件布局。
在调用时,可以在NavigationController中调用

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [super pushViewController:viewController animated:YES];
    [self.baseNaviBar remakeSubViewsForBackBtn];
}
/**
 清除返回按钮
 */
- (void)clearForBackBtn;

有创建也就有移除,返回到基础Tab页面时需要调用此方法来清除返回按钮。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.naviController.baseNaviBar updateNaviBarTitle:@"主页"];
    [self.naviController.baseNaviBar clearForBackBtn];
}
/**
单独添加一个右边的按钮
*/
- (void)addSingleRightBtnWithTitle:(NSString *)title ButtonImage:(NSString *)imageName Target:(id)target Action:(SEL)action;

刚刚提到右侧的功能键数量0-3个不等,这里先给到一个创建一个按钮的方法,方法参数中传入target以及点击事件。
此方法的实现中,除了给btn布局和添加点击事件以外,需要提一小点是

[self.rightButton setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];

设置约束的优先级,以免某些页面title文字过长导致和右侧按钮约束冲突。

/**
 添加自定义按钮
 由右向左添加!
 填入buttonTitles参数也按照从右向左的顺序。
 buttonConfiguration:
 @{
 @"title":@"标题",
 @"image":@"图片名",
 @"action":action,//button点击方法,传入NSInvocation类型参数
 }
 */
- (void)addButtonWithButtonConfiguration:(NSDictionary *)buttonConfiguration,...NS_REQUIRES_NIL_TERMINATION;

右侧有多个按钮的页面就由此方法来实现,比较关键的两点是:
1> NS_REQUIRES_NIL_TERMINATION 宏
在创建字典,数组时肯定没少用过这类方法

NSArray arrayWithObjects:<#(nonnull ObjectType), ...#>, nil

自己来实现这个写法时,核心代码如下:

- (void)addButtonWithButtonConfiguration:(NSDictionary *)buttonConfiguration, ... {
    va_list argList;
    if (buttonConfiguration) {
        va_start(argList, buttonConfiguration);
        NSDictionary *configuraDict;
        //这样每次循环argList所代表的指针偏移量就不断下移直到取出nil
        while ((configuraDict = va_arg(argList, id))) {
             //这里设置btn布局,添加点击事件
        }
    }
    va_end(argList);
}

2>传入NSInvocation类型参数
直接上代码,创建一个NSInvocation对象

+ (NSInvocation *)creatInvocationWithTarget:(id)target Action:(SEL)action {
    NSMethodSignature *signature = [target methodSignatureForSelector:action];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = target;
    invocation.selector = action;
    return invocation;
}

NSInvocation有其他更有趣好用的使用场景,在此处大材小用了,仅仅是因为需要作为参数包装到字典中,其他用法这里先不赘述了。

添加btn方法调用示例如下:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.naviController.baseNaviBar updateNaviBarTitle:@"主页"];
    [self.naviController.baseNaviBar clearForBackBtn];

    [self.naviController.baseNaviBar addButtonWithButtonConfiguration:
     @{@"title":@"btn1",@"image":@"image1",@"action":[CreatActionTool creatInvocationWithTarget:self Action:@selector(click1)]},
     @{@"title":@"btn2",@"image":@"image2",@"action":[CreatActionTool creatInvocationWithTarget:self Action:@selector(click2)]},nil];
}

在添加btn点击事件时如下:

 NSInvocation *action = [configuraDict objectForKey:@"action"];//configuraDict为在上述方法中循环取出的btn配置数据
 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
 [button addTarget:action.target action:action.selector forControlEvents:UIControlEventTouchUpInside];


提供主要功能的几个方法如上所述,还可以随意添加一些自定义功能。
因为代码中为了项目需求,做了好多适配,也不是通用的方法,后面整理好再上传~

你可能感兴趣的:(iOS- 一种自定义NavigationBar的方式)