距離上一篇《第一個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;
}