(2)微博主框架-自定义导航控制器NavigationController

最后更新于:2022-04-01 07:26:56

## 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController)。 为啥要做自定义呢,因为为了更好地封装代码,并且系统的UINavigationController不能满足我们的需求了,所以得自定义。 首先,我们在NYTabBarViewController的  - (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage方法中写了这个: ~~~ // 先给外面传进来的小控制器 包装 一个导航控制器 NYNavigationController *nav = [[NYNavigationController alloc] initWithRootViewController:childVc]; // 添加为子控制器 [self addChildViewController:nav]; ~~~ 来给设置的各个Controller包装一个导航控制器。 这时候系统会自动给添加一个。然后呢我们要对导航控制器进行改进。 ### 框架结构 目前情况下的UI架构如下图所示:一个IWTabBarController拥有4个导航控制器作为子控制器,每个导航控制器都有自己的根控制器(栈底控制器)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d96d5886.jpg) * * * ### 重要代码 1.给控制器包装一个导航控制器并且放入tabbarController中 ~~~ // 先给外面传进来的小控制器 包装 一个导航控制器 NYNavigationController *nav = [[NYNavigationController alloc] initWithRootViewController:childVc]; // 添加为子控制器 [self addChildViewController:nav]; ~~~ * * * ## 二:导航控制器左右item的设置 在NYMessageCenterViewController中我们添加了cell,并使之可以点击,点击后进入到另一个界面(test1) 再点击界面的view进入另外一个界面(test2) 首先放入20行假数据——UITableView的数据源方法 返回一组,20行,每行内容cell设置 ~~~ #pragma mark - Table view data source 数据源方法 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete method implementation. // Return the number of rows in the section. return 20; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"ID"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } cell.textLabel.text = [NSString stringWithFormat:@"test~~~~message - %d", indexPath.row]; return cell; } ~~~ 然后是cell的点击方法了 不用死记全部方法名字,简单敲一下tableview 查找didSele方法(学iOS对英语挺高老快了)灵活运用xcode的自动提示功能。 ~~~ #pragma mark - 代理方法 //cell的点击事件 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NYTest1ViewController *test1 = [[NYTest1ViewController alloc] init]; test1.title = @"测试1控制器"; [test1.navigationController setNavigationBarHidden:NO]; [self.navigationController pushViewController:test1 animated:YES]; } ~~~ test1是我们自己做的一个测试类,其中我们做了两个如图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d96ee815.jpg) 这时候,我们的消息界面就有了cell的数据并且可以点击了。如图效果:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d970cdd6.jpg)  (到test2的push和1的一样,不过是用的view的touch方法) 这时候我们要做导航控制器的左右item了。  然后我们设置导航控制器的左右item (写私信按钮等)  如图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d97344b7.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9746bda.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9756390.jpg) ~~~ - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"写私信" style:UIBarButtonItemStylePlain target:self action:@selector(composeMsg)]; //设置右侧按钮为不可点击状态 self.navigationItem.rightBarButtonItem.enabled = NO; NYLog(@"NYMessageCenterViewController-viewDidLoad"); } ~~~ 其中的UIBarButtonItem 的创建方法不是系统给的,而是我们为了实现黄色的效果自己写的分类实现的。 ### 分类实现UIBarButtonItem的自定义创建方法: ~~~ // // UIBarButtonItem+Extension.m // 猫猫微博 // // Created by apple on 15-6-4. // Copyright (c) 2015年 znycat. All rights reserved. // #import "UIBarButtonItem+Extension.h" @implementation UIBarButtonItem (Extension) /** * 创建一个item * * @param target 点击item后调用哪个对象的方法 * @param action 点击item后调用target的哪个方法 * @param image 图片 * @param highImage 高亮的图片 * * @return 创建完的item */ +(UIBarButtonItem *)itemWithTarget:(id)target action:(SEL)action image:(NSString *)image highImage:(NSString *)highImage { UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom]; //设置图片 [backBtn setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal]; [backBtn setBackgroundImage:[UIImage imageNamed:highImage] forState:UIControlStateHighlighted]; [backBtn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; //设置尺寸 CGSize imageSize = backBtn.currentBackgroundImage.size; backBtn.frame = CGRectMake(0, 0, imageSize.width, imageSize.height); UIBarButtonItem *itemBtn = [[UIBarButtonItem alloc] initWithCustomView:backBtn]; return itemBtn; } @end ~~~ 这里设置尺寸用到了 ~~~ CGSize imageSize = backBtn.currentBackgroundImage.size; ~~~ 在我们学习UI的transform的时候,我们知道 是不能直接这么设置size的,但是为啥这里能呢? 很简单 ,我们对UIView写了一个分类 ~~~ // // UIView+Extension.m // 猫猫微博 // // Created by apple on 15-6-2. // Copyright (c) 2015年 znycat. All rights reserved. // #import "UIView+Extension.h" @implementation UIView (Extension) -(void)setX:(CGFloat)x { CGRect frame = self.frame; frame.origin.x = x; self.frame = frame; } -(CGFloat)x { return self.frame.origin.x; } -(void)setY:(CGFloat)y { CGRect frame = self.frame; frame.origin.y = y; self.frame = frame; } -(CGFloat)y { return self.frame.origin.y; } -(void)setWidth:(CGFloat)width { CGRect frame = self.frame; frame.size.width = width; self.frame = frame; } -(CGFloat)width { return self.frame.size.width; } -(void)setHeight:(CGFloat)height { CGRect frame = self.frame; frame.size.height = height; self.frame = frame; } -(CGFloat)height { return self.frame.size.height; } -(void)setSize:(CGSize)size { CGRect frame = self.frame; frame.size = size; self.frame = frame; } -(CGSize)size { return self.frame.size; } -(void)setOrigin:(CGPoint)origin { CGRect frame = self.frame; frame.origin = origin; self.frame = frame; } -(CGPoint)origin { return self.frame.origin; } @end ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d97344b7.jpg)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9746bda.jpg)  并且为了改变系统原生的 美丽的蓝色情调,换成微博的黄色。。。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9777370.jpg) 我们要重写NYNavigationController初始加载方法 (initialize)以及重写pushViewController方法,让push 的时候会自动带着箭头按钮和右边的更多按钮(UIBarButtonItem) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9756390.jpg) ~~~ // // NYNavigationController.m // 猫猫微博 // // Created by apple on 15-6-4. // Copyright (c) 2015年 znycat. All rights reserved. // #import "NYNavigationController.h" @interface NYNavigationController () @end @implementation NYNavigationController +(void)initialize { // 设置整个项目所有item的主题样式 UIBarButtonItem *item = [UIBarButtonItem appearance]; // 普通状态 NSMutableDictionary *textAttrsNormal = [NSMutableDictionary dictionary]; textAttrsNormal[NSForegroundColorAttributeName] = [UIColor orangeColor]; textAttrsNormal[NSFontAttributeName] = [UIFont systemFontOfSize:14]; [item setTitleTextAttributes:textAttrsNormal forState:UIControlStateNormal]; // 不可用状态 NSMutableDictionary *textAttrsDisabled = [NSMutableDictionary dictionary]; textAttrsDisabled[NSFontAttributeName] = [UIFont systemFontOfSize:14]; textAttrsDisabled[NSForegroundColorAttributeName] = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:0.7]; [item setTitleTextAttributes:textAttrsDisabled forState:UIControlStateDisabled]; } /** * 重写这个方法目的:能够拦截所有push进来的控制器 * * @param viewController 即将push进来的控制器 */ -(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // 这时push进来的控制器viewController,不是第一个子控制器(不是根控制器) if (self.viewControllers.count > 0) { /* 自动显示和隐藏tabbar */ viewController.hidesBottomBarWhenPushed = YES; // 设置左边的箭头按钮 viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(back) image:@"navigationbar_back" highImage:@"navigationbar_back_highlighted"]; // 设置右边的更多按钮 viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(more) image:@"navigationbar_more" highImage:@"navigationbar_more_highlighted"]; } [super pushViewController:viewController animated:animated]; } -(void)back { #warning 这里要用self,不是self.navigationController // 因为self本来就是一个导航控制器,self.navigationController这里是nil的 [self popViewControllerAnimated:YES]; } -(void)more { //回到根 [self popToRootViewControllerAnimated:YES]; } @end ~~~ 最后就是各个页面的调用了  首页:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d97344b7.jpg) ~~~ - (void)viewDidLoad { [super viewDidLoad]; /* 设置导航栏上面的内容 */ self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(friendSearch) image:@"navigationbar_friendsearch" highImage:@"navigationbar_friendsearch_highlighted"]; self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(pop) image:@"navigationbar_pop" highImage:@"navigationbar_pop_highlighted"]; } ~~~ 我:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9777370.jpg) ~~~ - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"设置" style:0 target:self action:@selector(setting)]; } ~~~ 消息里面的写私信(这里设置默认不可用状态)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-20_569f1d9746bda.jpg) ~~~ - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"写私信" style:UIBarButtonItemStylePlain target:self action:@selector(composeMsg)]; //设置右侧按钮为不可点击状态 self.navigationItem.rightBarButtonItem.enabled = NO; NYLog(@"NYMessageCenterViewController-viewDidLoad"); } ~~~
';