iOS- 一种自定义NavigationBar的方式

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

先看下项目界面简图:

界面.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];


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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 程孤帆不解其意,走过去才见里面数层放着一卷卷东西。 他随手拣起一卷,见封皮上写着“千秋山庄”。数十年前,千秋山庄全...
    德万托阿阅读 591评论 0 5
  • 【周检视】2017年8月14日-8月20日 好好读书,好好健身,好好爱自己 一 健康 这一周每天都有坚持5.30打...
    huiyoulanda阅读 175评论 0 0