距离上一篇《第一个iOS应用》已经有一个多月了,今天来和大家一起学习和分享一下一个小练习《网易彩票》
首先我们向storyboard中拖入一个TabBarController和5个NavigationController,如下:
我们先来看看什么是导航控制器
1、导航控制器
“如果应用程序有多个内容视图层次,就需要能够在它们之间进行切换。为此,可以使用专门的视图控制器:导航控制器 (UINavigationController)。导航控制器管理在一系列视图控制器中向后和向前切换的操作,例如用户在 iOS 版“邮件”应用程序的电子邮件帐户、收件箱邮件和单封电子邮件之间导航。
我们将由特定导航控制器所管理的一组视图控制器称为其导航栈。导航栈是一组后进先出的自定视图控制器对象。添加到堆栈的第一个项目将变成根视图控制器,永不会从堆栈中弹出。而其他视图控制器可被压入或弹出导航栈。
虽然导航控制器的最主要作用是管理内容视图控制器的显示方式,但它还负责显示自己的自定视图。具体来说,它会显示导航栏(位于屏幕顶部的视图,提供有关用户在导航层次中位置的上下文)。导航栏包含一个返回按钮和其他可以自定的按钮。添加到导航栈的每个视图控制器都会显示这个导航栏。您需要配置导航栏。
一般而言,您不必执行任何操作来将视图控制器弹出导航栈;导航控制器提供的返回按钮会实现该操作。但您需要手动将视图控制器压入堆栈中。可使用串联图来操作。”
有如下几个类型过度
Push:Push 过渡将目的视图控制器添加到导航栈。只有当源视图控制器与导航控制器连接时,才可以使用 Push 过渡。
Modal:简单而言,Modal 过渡就是一个视图控制器以模态方式显示另一个控制器,需要用户在显示的控制器上执行某种操作,然后返回到应用程序的主流程。Modal 视图控制器不会添加到导航栈;相反,它通常被认为是所显示的视图控制器的子视图控制器。显示的视图控制器的作用是关闭它所创建和显示的 Modal 视图控制器。
Custom:可以通过将 UIStoryboardSegue 子类化来定义自定过渡。
Unwind:Unwind 过渡通过向后移动一个或多个过渡,让用户返回到视图控制器的当前实例。使用 Unwind 过渡可以实现反向导航。
除了过渡之外,还可以通过关系来连接场景。例如,导航控制器与其根视图控制器之间就存在关系。就此而言,这种关系表示导航控制器包含根视图控制器。
使用串联图规划应用程序的用户界面时,要确定将其中一个视图控制器标记为初始视图控制器,这一点尤为重要。运行时,该视图控制器的内容视图会在应用程序首次启动时显示,且在需要时,您可以从该视图控制器切换到其他视图控制器的内容视图。
上图表示一种包含关系
关于storyboard详细请看:https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/AboutStoryboards.html#//apple_ref/doc/uid/TP40014225-CH41-SW1
"A navigation controller object manages the currently displayed screens using the navigation stack, which is represented by an array of view controllers."
上面是官网对导航控制器的描述,大意是,一个导航控制器通过导航栈管理着一组视图控制器来控制当前显示的屏幕视图(英文很烂)
二、自定义TabBar
新建CustomTabBar继承字UIView
#import <UIKit/UIKit.h> @interface CustomTabBar : UIView @end
要能访问到UITabBar就要重新写UITabBarController
#import "CustomTabBarController.h" #import "CustomTabBar.h" @interface CustomTabBarController () @end @implementation CustomTabBarController - (void)viewDidLoad { [super viewDidLoad]; //移除系统自带的tabBar [self.tabBar removeFromSuperview]; //添加自己的tabBar CustomTabBar *myTabBar = [[CustomTabBar alloc] init]; myTabBar.frame = self.tabBar.frame; myTabBar.backgroundColor = [UIColor greenColor]; [self.view addSubview:myTabBar]; //添加5个按钮 for (int i = 0; i < 5; i++) { //创建按钮 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; //设置图片 NSString *name = [NSString stringWithFormat:@"TabBar%d", i + 1]; [button setBackgroundImage:[UIImage imageNamed:name] forState:(UIControlStateNormal)]; //设置frame CGFloat buttonY = 0; CGFloat buttonW = myTabBar.frame.size.width * 0.2; CGFloat buttonH = myTabBar.frame.size.height; CGFloat buttonX = i * buttonW; button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH); //添加 [myTabBar addSubview:button]; } } @end
三、实现标签导航效果
如上图所示,建立Relationship Segue
工程目录如下:
首先,自定义TabBarButton
#import "CustomTabBarButton.h" @implementation CustomTabBarButton - (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if(self){ } return self; } //覆盖该方法,按钮就不存在高亮状态 - (void)setHighlighted:(BOOL)highlighted{ } @end
自定义TabBar
#import <UIKit/UIKit.h> @class CustomTabBar; @protocol MyTabBarDelegate <NSObject> @optional - (void)tabBar:(CustomTabBar *)tabBar didSelectButtonFrom:(int)from to:(int)to; @end @interface CustomTabBar : UIView @property (nonatomic, weak) id<MyTabBarDelegate> delegate; /** * 用来添加一个内部的按钮 * * @param name 按钮图片 * @param selName 按钮选中时的图片 */ - (void)addTabButtonWithName:(NSString *)name selName:(NSString *)selName; @end
#import "CustomTabBar.h" #import "CustomTabBarButton.h" @interface CustomTabBar() //记录当前选中的按钮 @property (nonatomic, weak)CustomTabBarButton *selectedButton; @end @implementation CustomTabBar - (void)addTabButtonWithName:(NSString *)name selName:(NSString *)selName{ //创建按钮 CustomTabBarButton *button = [CustomTabBarButton buttonWithType:UIButtonTypeCustom]; //设置图片 [button setBackgroundImage:[UIImage imageNamed:name] forState:UIControlStateNormal]; [button setBackgroundImage:[UIImage imageNamed:selName] forState:UIControlStateSelected]; //添加按钮 [self addSubview:button]; //监听按钮按下 [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown]; //默认选择第0个按钮 if(self.subviews.count == 1){ [self buttonClick:button]; } } - (void) layoutSubviews{ [super layoutSubviews]; int count = self.subviews.count; for(int i = 0; i < count; i++){ CustomTabBarButton *button = self.subviews[i]; button.tag = i; //设置frame CGFloat buttonY = 0; CGFloat buttonW = self.frame.size.width / count; CGFloat buttonH = self.frame.size.height; CGFloat buttonX = i * buttonW; button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH); } } /** * 监听按钮点击 */ - (void)buttonClick:(CustomTabBarButton *)button{ //通知代理 if([self.delegate respondsToSelector:@selector(tabBar:didSelectButtonFrom:to:)]){ [self.delegate tabBar:self didSelectButtonFrom:self.selectedButton to:button.tag]; } //让当前选中的按钮取消选中 self.selectedButton.selected = NO; //让新点击的按钮选中 button.selected = YES; //新点击的按钮就成为了“当前选中的按钮” self.selectedButton = button; } @end
在上面我们定义了一个代理用来通知TabBar上面的选择事件(点击)事件。
最后在TabBarController中设置我们自定义的TabBar并处理选择的界面
#import "MyTabBarController.h" #import "CustomTabBar.h" #import "CustomTabBarButton.h" @interface MyTabBarController () <MyTabBarDelegate> @end @implementation MyTabBarController - (void)viewDidLoad { [super viewDidLoad]; //1.添加自己的tabbar CustomTabBar *customTabBar = [[CustomTabBar alloc] init]; customTabBar.delegate = self; customTabBar.frame = self.tabBar.bounds; [self.tabBar addSubview:customTabBar]; //2.添加对应个数的按钮 for(int i = 0; i < self.viewControllers.count; i++){ NSString *name = [NSString stringWithFormat:@"TabBar%d", i + 1]; NSString *selName = [NSString stringWithFormat:@"TabBar%dSel", i + 1]; [customTabBar addTabButtonWithName:name selName:selName]; } //3.设置导航栏外观 UINavigationBar *navBar = [UINavigationBar appearance]; [navBar setBackgroundImage:[UIImage imageNamed:@"NavBar64"] forBarMetrics:UIBarMetricsDefault]; } - (void)tabBar:(CustomTabBar *)tabBar didSelectButtonFrom:(int)from to:(int)to{ self.selectedIndex = to; } @end
四、设置导航栏和状态栏
我们重写NavigationController来实现导航栏的自定义
/** * 系统在第一次使用这个类的时候调用(1个类只会调用一次) */ + (void)initialize { // 设置导航栏主题 UINavigationBar *navBar = [UINavigationBar appearance]; // 设置背景图片 NSString *bgName = nil; if (iOS7) { // 至少是iOS 7.0 bgName = @"NavBar64"; } else { // 非iOS7 bgName = @"NavBar"; } [navBar setBackgroundImage:[UIImage imageNamed:bgName] forBarMetrics:UIBarMetricsDefault]; // 设置标题文字颜色 NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; attrs[UITextAttributeTextColor] = [UIColor whiteColor]; attrs[UITextAttributeFont] = [UIFont systemFontOfSize:16]; [navBar setTitleTextAttributes:attrs]; } /** * 重写这个方法,能拦截所有的push操作 * */ - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { viewController.hidesBottomBarWhenPushed = YES; [super pushViewController:viewController animated:animated]; }
上面判断了当前的sdk版本,如果是ios7以上则导航栏的高度应该是64,ios6则是44,使用两个不同的背景。
重写pushViewController方法实现对底部TabBar的隐藏做统一处理。
// 判断是否为iOS7 #define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue] >= 7.0)
在AppDelegate中设置状态栏的颜色
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // 设置状态栏的样式 application.statusBarStyle = UIStatusBarStyleLightContent; return YES; }