UITabBarController + UINavigationController复合架构设计

纯代码创建,不提倡使用XIB和故事版(storyboard),虽然提高开发速度,但是消耗性能。

1.先看控制器之间的层级关系:如下图所示

从这张图可以看到:最右边的Assembled views是呈现给用户的界面,它左边的Window是最底层的窗口,重点来了,再往左,是Tab bar view,Tab bar view的上方是Navigation view,最后是用户定制的视图。

2.了解以后,代码就应该很好写了。需要把Navigation view加到 Tab bar view的内容上去,Tab bar view再加到Window上去。就是Window套UITabBarController,UITabBarController套UINavigationController, UINavigationController套UIViewController。

3.

1、新建Single View Application项目

为了更好的理解,我们直接新建Single View Application

2、删除ViewController.h等3个文件

删除如下图所示的3个文件: 
ViewController.h、ViewController.m和Main.storyboard。

3、新建MainViewController

根据上面的层级关系图,我们需要把UITabBarController加到Window上去,所以在这里,我们直接新建MainViewController,让它继承UITabBarController,如下图所示:

点击Next,继承于UITabBarController,不用勾选Also Create XIB file,如下图:

4、修改AppDelegate.m文件

我们为了让MainViewController加到Window上去,修改AppDelegate.m文件,直接上代码,如下所示:

#import "AppDelegate.h"
#import "MainViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    MainViewController *mainVC = [[MainViewController alloc] init];
    self.window.rootViewController = mainVC;

    return YES;
}

5、新建两个标签页

新建FirstViewController和SecondViewController,继承于UIViewController,这里不用勾选Also create XIB file(这两张图片是截取的,不用勾选,后面全纯代码创建,为了提高代码维护性) 
如下图:

FirstViewController:

SecondViewController:

创建好后,现在的文件目录结构是这样的

6、修改MainViewController.m

现在,我们需要把刚才创建的页面(First/Second ViewController)加入到导航控制器,再把导航控制器加到标签控制器上去。

直接上代码:

#import "MainViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"

@interface MainViewController ()

@end

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 执行加载控制器
    [self loadViewControllers];
}

- (void)loadViewControllers {

    // 1.新建第一页视图控制器实例
    FirstViewController *firstVC = [[FirstViewController alloc] init];
    // 2.新建第一页导航控制器实例,把firstVC加入进去
    UINavigationController *firstNC = [[UINavigationController alloc] initWithRootViewController:firstVC];
    // 3.新建第一页的标签栏图标
    UITabBarItem *firstTabBarItem =[[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemBookmarks tag:0];
    // 4.图标加入到第一页的导航控制器上
    firstNC.tabBarItem = firstTabBarItem;

    // 第二页
    SecondViewController *secondVC = [[SecondViewController alloc] init];
    UINavigationController *secondNC = [[UINavigationController alloc] initWithRootViewController:secondVC];
    UITabBarItem *secondTabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemContacts tag:1];
    secondNC.tabBarItem = secondTabBarItem;

    // 5.新建一个导航控制器实例的数组
    NSArray *controllersArray = @[firstNC, secondNC];
    // 6.把导航控制器的数组加入到标签控制器
    [self setViewControllers:controllersArray animated:YES];

}

直接看代码注释就可以大致了解流程:UIViewController加到UINavigationController上,UINavigationController加入UITabBarController,跟上面的层级关系图相符。

我们现在可以运行一下,会提示如下错误:

‘NSInvalidArgumentException’, reason: ‘Could not find a storyboard named ‘Main’ in bundle NSBundle

看这个提示,原来是我们步骤2中删除了Main.storyboard,但是程序设置的Main Interface默认是Main,这肯定会报错了。我们需要修改一下项目的配置,就暂且改成LaunchScreen吧,如下图:

我们再次运行一下,应该是没问题的,效果已经出来了,如下图:

我们把每页的title加一下,方便看效果:

FirstViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    // 设置title
    self.title = @"main";
}

SecondViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    // 设置title
    self.title = @"second";
} 

再次运行,点击相应的标签图片,就可以看到效果了:

7、新建DetailsViewController

为了体现UINavigaitonController,我们需要再新建一个页面,然后在FirstViewController里增加一个按钮,点击按钮跳转到此页面,如下图:

文件新建好之后,我们给这个页面加上标题:

DetailsViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    // 设置title
    self.title = @"details";
}

我们接下来在FirstViewController里加一个按钮,然后连线到FirstViewController.m文件里实现点击事件,代码:

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view.

self.title = @"Main";

self.view.backgroundColor = [UIColor yellowColor];

UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 150, 50)];

btn.backgroundColor = [UIColor greenColor];

[btn setTitle:@"GO" forState:UIControlStateNormal];

[self.view addSubview:btn];

[btn addTarget:self action:@selector(goClick) forControlEvents:UIControlEventTouchUpInside];

}

- (void)goClick{

DetailsViewController * detail = [[DetailsViewController alloc]init];

//    隐藏标签栏

detail.hidesBottomBarWhenPushed = YES;

[self.navigationController pushViewController:detail animated:NO];

}

通过上面的代码,点击Go就可以跳转到DetailsViewController页面。

注意第四行,如果我们需要在进入Details页面之后隐藏底部的标签栏,可以在这里设置hidesBottomBarWhenPushed为YES。注意,在DetailsViewController.m文件中的viewDidLoad方法中调用是没效果的,在viewWillAppear里也不行,只有在init方法中调用才可以,如以下代码:

- (instancetype)init {
    self.hidesBottomBarWhenPushed = YES;
    return [super init];
}

再次运行,点击Go按钮,顺利跳转到了Details页面:

到此,就已经算是实现了TabBar和Navigation的整合使用。

美化


顶部导航栏

我们可以美化一下顶部导航栏,比如更改背景、文字颜色,还有状态栏文字颜色等。

MainViewController.m文件中的loadViewControllers方法,在新建firstNC实例之后,加入:

    // 设置导航栏背景图片(需要素材)
    [firstNC.navigationBar setBackgroundImage:[UIImage imageNamed:@"bg"] forBarMetrics:UIBarMetricsDefault];
    // 设置导航栏样式
    [firstNC.navigationBar setBarStyle:UIBarStyleBlackTranslucent];
    // 设置返回按钮文字和图标颜色
    [firstNC.navigationBar setTintColor:[UIColor whiteColor]];

加入上述代码之后,再次运行,可以看到导航栏和状态栏的文字颜色已经更改

进入details页面

底部标签栏

当然,底部的标签栏也可以更改背景,在MainViewController.m的viewDidLoad方法中:

- (void)viewDidLoad {
    [super viewDidLoad];

    // 执行加载控制器
    [self loadViewControllers];
    //设置底部标签栏背景
    [self.tabBar setBackgroundImage:[UIImage imageNamed:@"bg"]];

}

还可以自定义每个标签默认和选中的图片,拷入素材图片之后, 
在MainViewControllers中,重新定义第一个标签栏Item:

    // 自定义显示的图片
    UIImage *homeNormal = [UIImage imageNamed:@"home_normal"];
    UITabBarItem *firstTabBarItem = [[UITabBarItem alloc] initWithTitle:@"Main" image:homeNormal tag:0];

最终效果,如下图:

时间: 2024-11-09 01:39:54

UITabBarController + UINavigationController复合架构设计的相关文章

架构设计:系统存储(8)——MySQL数据库性能优化(4)

================================ (接上文<架构设计:系统存储(7)--MySQL数据库性能优化(3)>) 4-3.InnoDB中的锁 虽然锁机制是InnoDB引擎中为了保证事务性而自然存在的,在索引.表结构.配置参数一定的前提下,InnoDB引擎加锁过程是一样的,所以理论上来说也就不存在"锁机制能够提升性能"这样的说法.但如果技术人员不理解InnoDB中的锁机制或者混乱.错误的索引定义和同样混乱的SQL写操作语句共同作用,那么导致死锁出现的

架构设计:系统存储(9)——MySQL数据库性能优化(5)

=================================== (接上文<架构设计:系统存储(9)--MySQL数据库性能优化(5)>) 4-3-3-3.避免死锁的建议 上一篇文章我们主要介绍了MySQL数据库中锁的基本原理.工作过程和产生死锁的原因.通过上一篇文章的介绍,可以确定我们需要业务系统中尽可能避免死锁的出现.这里为各位读者介绍一些在InnoDB引擎使用过程中减少死锁的建议. 正确使用读操作语句 经过之前文章介绍,我们知道一般的快照读是不会给数据表任何锁的.那么这些快照读操作

微信红包的架构设计简介

@来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微信红包的架构,于是乎有了下面的文字(有误请提出,谢谢) 概况:2014年微信红包使用数据库硬抗整个流量,2015年使用cache抗流量. 微信的金额什么时候算? 答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储.. 采取实时计算金额的考虑:预算需要占存储,实时效率很高,预算才效率低. 实时性:为什么明明抢到红包,点开后发现没有? 答:2014年的红包一点开就知道金额,分两次操作

mysql性能调优与架构设计笔记

1.mysql基本介绍 mysql支持多线程高并发的关系型数据库; 数据库存储引擎InnoDB.MyISAM; mysql快速崛起的原因就是他是开源的; 性能一直是mysql自豪的一大特点; 2.mysql架构组成 麻雀虽小五脏俱全,mysql虽然简单但其内部结构并不简单; mysql物理文件组成之日志文件: 错误日志error log这里记录mysql运行时严重的警告和错误,以及mysql启动和关闭的日志信息 二进制日志 binary log 记录mysql运行时所有的query和query执

《游戏架构设计与策划基础》笔记 第一章 游戏策划概述(上)

1.1 什么是游戏策划 游戏的目的就是通过玩来获得娱乐,因此,设计游戏既需要艺术家一样的创造力,也需要工程师一样的精心规划.游戏设计是一门手艺,就像是好莱坞的电影摄像或服装设计一样.一个游戏既含有艺术要素,也含有功能要素:它必须能给人以美的享受,同时又必须能很好地运行,让游戏者享受到快乐.具备这两种特点的游戏才是好的游戏. 1.2 游戏策划的任务 游戏策划根据自己的创作理念,结合市场调研得来的数据,参考其他开发人员的意见和建议,在开发条件允许的基础上,将游戏创意以及游戏内容和规则细化完整,形成策

架构设计:系统间通信(32)——其他消息中间件及场景应用(下2)

(接上文<架构设计:系统间通信(31)--其他消息中间件及场景应用(下1)>) 5-3.解决方案二:改进半侵入式方案 5-3-1.解决方法一的问题所在 方案一并不是最好的半侵入式方案,却容易理解架构师的设计意图:至少做到业务级隔离.方案一最大的优点在于日志采集逻辑和业务处理逻辑彼此隔离,当业务逻辑发生变化的时候,并不会影响日志采集逻辑. 但是我们能为方案一列举的问题却可以远远多于方案一的优点: 需要为不同开发语言分别提供客户端API包.上文中我们介绍的示例使用JAVA语言,于是 事件/日志采集

web架构设计经验分享(转)

本人作为一位web工程师,着眼最多之处莫过于 性能与架构,本次幸得参与sd2.0大会,得以与同行广泛交流,于此二方面,有些心得,不敢独享,与众博友分享,本文是这次参会与众同撩交流的心得,有兴趣者可以查看视频 架构设计的几个心得: 一,不要过设计:never over design 这是一个常常被提及的话题,但是只要想想你的架构里有多少功能是根本没有用到,或者最后废弃的,就能明白其重要性了,初涉架构设计,往往倾向于设计大而化一的架构,希望设计出具有无比扩展性,能适应一切需求的增加架构,web开发领

垂直型爬虫架构设计(2)

上文提到了关于爬虫的一些简单概念与爬虫真正要做的一些功能.简单的分析了一下垂直型爬虫与宽度(深度)遍历的一些特点.现在,我主要针对于垂直型爬虫的架构设计做一些简单的介绍. 1.垂直型爬虫的基本需求 目前企业级所需的基本上是垂直型爬虫.舆情分析,财经资讯资讯推荐等.基本山使用的都是垂直型爬虫来作为企业级使用的方案,企业级爬虫的特点我上篇博客里面已经讲过了,所以在做垂直型爬虫架构的时候只需要考虑抓去内容所需的功能.简单来说:拿到某篇资讯所需的方式或功能.例如:常见的 javascript方式,aja

Swing程序最佳架构设计—以业务对象为中心的MVC模式(转)

前言: 我打算写一系列关于Swing程序开发的文章.这是由于最近我在做一个Swing产品的开发.长期做JavaEE程序,让我有些麻木了.Swing是设计模式的典范,是一件优雅的艺术品,是一件超越时代的产品! 有机会作Swing软件的开发,让我非常有感觉! 呵呵,希望有机会能够用Java3D编写软件,那种感觉一定更棒! Java和Swing都是杰作.我这个人对别人一向很挑剔的,能够得到我由衷地赞誉,可想而知它们有多优秀了.奇怪的是,它们居然一直都无法占领桌面市场.有人说这是技术的原因.我认为这应该