這一篇我們將學(xué)習(xí)一個(gè)新的控件Navigation Controller,很多時(shí)候Navigation Controller是和Table View緊密結(jié)合在一起的,因此在學(xué)習(xí)Navigation Controller的同時(shí),我們還將繼續(xù)學(xué)習(xí)Table View其他一些特性,畢竟Navigation Controller還是相對(duì)來(lái)說(shuō)畢竟簡(jiǎn)單的,沒(méi)有什么太大的花頭,它的主要作用就是一個(gè)view的切換,切來(lái)切去,而Table View的花頭就比較多了,這次我們將這2個(gè)控件結(jié)合在一起進(jìn)行學(xué)習(xí)。
再多說(shuō)一些關(guān)于Navigation Controller,Navigation Controller相信大家都見(jiàn)到過(guò),打開(kāi)你的iphone,在設(shè)置(Settings)里,選擇通用(General),最最上面的就是Navigation Controller,它的左邊是一個(gè)按鈕(稱(chēng)之為Navigation Button),點(diǎn)擊按鈕切換到前一個(gè)view,中間有一個(gè)title,顯示當(dāng)前view的title,Navigation Controller的下面就是一個(gè)Table View。
Navigation Controller對(duì)view的切換是有前后順序的,即從哪個(gè)view切換過(guò)來(lái),然后切換回去的時(shí)候還是這個(gè)view,他們之間的順序是不變的,你可以理解Navigation Controller就像一個(gè)棧(Stack)先進(jìn)后出,對(duì)比與之前在第11篇中學(xué)習(xí)的Tab Bar,Tab Bar也是用來(lái)控制view之間的切換的,但是它是任意切換,各個(gè)view之間沒(méi)有前后關(guān)系。Navigation Controller的view的組織結(jié)構(gòu)也和Tab Bar是很相似的,它也有一個(gè)根view(root view)用來(lái)控制其他的views,好了,下面開(kāi)始我們這次的學(xué)習(xí)內(nèi)容。
1)創(chuàng)建一個(gè)工程,選擇Empty application,將工程名命名為“Nav”
2)創(chuàng)建Top-Level View Controller(root view controller)
選中PRoject navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,或者使用快捷鍵command+N,或者使用菜單欄File>New>New File...,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點(diǎn)擊Next按鈕,在下一個(gè)窗口中將class命名為BIDFirstLevelController,Subclass of命名為UITableViewController
點(diǎn)擊Next按鈕,完成創(chuàng)建。
BIDFirstLevelController是一個(gè)root view controller,用來(lái)控制其他的view,也是程序啟動(dòng)時(shí),第一個(gè)載入的view。
下面打開(kāi)BIDAppDelegate.h,添加如下代碼
#import <UIKit/UIKit.h>@interface BIDAppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (strong, nonatomic) UINavigationController *navController;@end
我們添加了一個(gè)UINavigationController的對(duì)象,接著打開(kāi)BIDAppDelegate.m,添加如下code
#import "BIDAppDelegate.h"#import "BIDFirstLevelController.h"@implementation BIDAppDelegate@synthesize window = _window;@synthesize navController;- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. BIDFirstLevelController *first = [[BIDFirstLevelController alloc] initWithStyle:UITableViewStylePlain]; self.navController = [[UINavigationController alloc] initWithRootViewController:first]; [self.window addSubview:navController.view]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
這里主要解釋application:didFinishLauchingWithOptions方法中新添加的3行代碼:
BIDFirstLevelController *first = [[BIDFirstLevelController alloc] initWithStyle:UITableViewStylePlain];
創(chuàng)建一個(gè)BIDFirstLevelController的對(duì)象,BIDFirstLevelController繼承自UITableViewController,因此它可以使用UITableViewController中的方法,包括聲明時(shí)用到的initWithStyle:UITableViewStylePlain(UITableViewStylePlain之前的章節(jié)講到過(guò),table view的2中表現(xiàn)形式plain和grouped)
self.navController = [[UINavigationController alloc] initWithRootViewController:first];
接著,創(chuàng)建UINavigationController的對(duì)象,使用的初始化的方式是initWithRootViewController,然后參數(shù)是first。這個(gè)初始化的意思是當(dāng)載入程序時(shí),在navigator下顯示的第一個(gè)view(root view)是什么(navigator總是需要一個(gè)view和它配合著一起工作,否則孤零零的一個(gè)navigator在那邊,下面什么都沒(méi)有,就沒(méi)有意義了),這里指定的root view是BIDFirstLevelController的對(duì)象。
[self.window addSubview:navController.view];
將navController的view添加到window中用于程序啟動(dòng)時(shí)顯示(之前的文章應(yīng)該講到過(guò),iphone有且只有一個(gè)window,我個(gè)人覺(jué)得可以認(rèn)為就是iphone的屏幕,且只有一個(gè),然后一個(gè)程序運(yùn)行時(shí)需要顯示,這時(shí)候必須告訴iphone的window那個(gè)view是第一個(gè)顯示的,第一個(gè)顯示的view也叫root view),在這里就是告訴iphone的window,第一個(gè)顯示的view是navController的view。
簡(jiǎn)單的總結(jié)一下上面3句話(huà)的含義,就是程序啟動(dòng)后在iphone的window中首先顯示navController的view,然后在navController的view中顯示BIDFirstLevelController。Navigator Controller的view有2部分組成,最上面的navigator bar和下面的內(nèi)容view(在這個(gè)例子中,下面的內(nèi)容view我們指定為BIDFirstLevelController)
至此,我們整個(gè)的程序結(jié)構(gòu)已經(jīng)搭建完畢了,接下來(lái)需要做的就是實(shí)現(xiàn)BIDFirstLevelController中的內(nèi)容,然后添加其他的table view用于view的切換,但是這些操作都是基于這個(gè)結(jié)構(gòu)的,理解了上面的內(nèi)容,下面的內(nèi)容學(xué)習(xí)起來(lái)就會(huì)游刃有余了。
我們編譯運(yùn)行一下code,看看效果
發(fā)現(xiàn)除了最上面的navController和下面的BIDFirstLevelController,其他什么都沒(méi)有,但是你要知道這些東西是怎么來(lái)的,他們之間的關(guān)系是什么就可以了。
3)實(shí)現(xiàn)BIDSecondLevelViewController
我們新添加一個(gè)類(lèi),叫做BIDSecondLevelViewController,這個(gè)類(lèi)繼承自UITableViewController,是所有subtableview的基類(lèi)。
選中Project navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點(diǎn)擊Next按鈕,在下一個(gè)窗口中將class命名為BIDSecondLevelViewController,Subclass of命名為UITableViewController,點(diǎn)擊Next按鈕,完成創(chuàng)建。
打開(kāi)BIDSecondLevelViewController.h,添加如下代碼
#import <UIKit/UIKit.h>@interface BIDSecondLevelViewController : UITableViewController@property (strong, nonatomic) UIImage *rowImage;@end
打開(kāi)BIDSecondLevelViewController.m
#import "BIDSecondLevelViewController.h"@implementation BIDSecondLevelViewController@synthesize rowImage;@end
我們僅僅在代碼中添加了一個(gè)UIImage,這樣,當(dāng)所有的subtableview繼承BIDSecondLevelViewController后,他們也就有了UIImage屬性,而不必每個(gè)subtableview定義各自的UIImage了。
4)實(shí)現(xiàn)BIDFirstLevelController
打開(kāi)BIDFirstLevelController.h,添加如下代碼
#import <UIKit/UIKit.h>@interface BIDFirstLevelController : UITableViewController@property (strong, nonatomic) NSArray *controllers;@end
這里僅僅添加了一個(gè)NSArray,它將保存所有的子table view
BIDFirstLevelController.m,添加如下代碼
#import "BIDFirstLevelController.h"#import "BIDSecondLevelViewController.h"@implementation BIDFirstLevelController@synthesize controllers;- (void)viewDidLoad { [super viewDidLoad]; self.title = @"First Level"; NSMutableArray *array = [[NSMutableArray alloc] init]; self.controllers = array;}- (void)viewDidUnload { [super viewDidUnload]; self.controllers = nil;}#pragma mark -#pragma mark Table Data Source Methods- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.controllers count];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *FirstLevelCell = @"FirstLevelCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelCell]; if(cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:FirstLevelCell]; } //configure the cell NSUInteger row = [indexPath row]; BIDSecondLevelViewController *controller = [controllers objectAtIndex:row]; cell.textLabel.text = controller.title; cell.imageView.image = controller.rowImage; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; return cell;}#pragma mark -#pragma mark Table View Delegate Methods- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger row = [indexPath row]; BIDSecondLevelViewController *nextController = [self.controllers objectAtIndex:row]; [self.navigationController pushViewController:nextController animated:YES];}@end
首先引入BIDSecondLevelViewController的頭文件,這樣BIDFirstLevelController就可以對(duì)它的對(duì)象進(jìn)行操作(可以對(duì)rowImage進(jìn)行操作)。
viewDidLoad方法:
self.title = @"First Level"; //對(duì)title進(jìn)行賦值,navigator controller會(huì)很聰明的知道當(dāng)前顯示的table view的title是什么,并把這個(gè)title顯示在自己的上面(剛才上面運(yùn)行的畫(huà)面,navigator controller上面是空的,什么都沒(méi)有,這個(gè)是因?yàn)閯偛胚€沒(méi)有實(shí)現(xiàn)BIDFirstLevelController,現(xiàn)在如果再運(yùn)行程序,你會(huì)發(fā)現(xiàn)navigator controller上面會(huì)顯示“First Level”)。
NSMutableArray *array = [[NSMutableArrayalloc] init]; //聲明一個(gè)NSMutableArray對(duì)象,之后我們將把每一個(gè)實(shí)現(xiàn)的子table view添加到這個(gè)對(duì)象中,因此我們這里聲明的是mutableArray,我們需要對(duì)其進(jìn)行添加操作(之前有例子我們聲明為immutable,我們不需要對(duì)其進(jìn)行添加刪除操作)
tableView:numberOfRowsInSection方法就不解釋了,作用和之前幾篇的例子一樣。
tableView:cellForRowAtIndexPath方法的前半部分是和之前的例子是一樣的,后半部分,從array中取出一個(gè)subtableview(每個(gè)subtableview都繼承自BIDSecondLevelViewController,因此可以將其類(lèi)型轉(zhuǎn)換為其基類(lèi)類(lèi)型),獲取其title和rowImage并賦值給cell的textLabel和imageView,最后定義cell的accessoryType。
tableView:didSelectRowAtIndexPath方法,當(dāng)我們點(diǎn)擊table view的某一行是,會(huì)觸發(fā)這個(gè)方法,這里實(shí)現(xiàn)的功能是點(diǎn)擊后,切換到當(dāng)前cell對(duì)應(yīng)的subtableview。
NSUInteger row = [indexPath row]; //獲取當(dāng)前點(diǎn)擊的是哪一行
BIDSecondLevelViewController *nextController = [self.controllers objectAtIndex:row]; //根據(jù)點(diǎn)擊的行,獲得array中相應(yīng)的subtableview
[self.navigationController pushViewController:nextController animated:YES]; //將對(duì)應(yīng)subtableview推入棧
還好,上面的實(shí)現(xiàn)總的來(lái)說(shuō)還算簡(jiǎn)單,我們?cè)诖司幾g運(yùn)行一下程序,效果如下
最最主要的變化就是navigator上面顯示了當(dāng)前table view的title“First Level”,其他的變化似乎還不是很大,但是其后面的變化已經(jīng)很巨大,接下來(lái)我們將添加5個(gè)subtableview,逐漸完成這個(gè)程序。
(先下載這里的圖標(biāo)Nav_Image,解壓縮后拖到Project navigator中的Nav文件夾下,直接拖進(jìn)去就可以)
5)第一個(gè)subtableview:The Disclosure Button View
所謂disclosure button,就是指table view中的藍(lán)色圓圈箭頭按鈕,如下
點(diǎn)擊這個(gè)按鈕后,會(huì)轉(zhuǎn)向下一個(gè)table view。
簡(jiǎn)單說(shuō)一下這個(gè)例子,首先會(huì)在root view中有一個(gè)cell與之關(guān)聯(lián),點(diǎn)擊該行cell會(huì)轉(zhuǎn)到該table view,然后這個(gè)table view中有很多cell,每一個(gè)cell都有一個(gè)textLabel和一個(gè)disclosure button,點(diǎn)擊cell(不點(diǎn)擊disclosure button)會(huì)有一個(gè)警告框彈出,點(diǎn)擊disclosure button,會(huì)轉(zhuǎn)到下一個(gè)table view顯示詳細(xì)內(nèi)容。
好了,現(xiàn)在開(kāi)始這個(gè)例子,首先選中Project navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點(diǎn)擊Next按鈕,在下一個(gè)窗口中將class命名為BIDDisclosureButtonController,Subclass of命名為BIDSecondLevelViewController,點(diǎn)擊Next按鈕,完成創(chuàng)建。
BIDDisclosureButtonController上面會(huì)放置很多個(gè)cell,每個(gè)cell都有一個(gè)textLabel和一個(gè)disclosure button
再次選中Project navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點(diǎn)擊Next按鈕,在下一個(gè)窗口中將class命名為BIDDisclosureDetailController,Subclass of命名為UIViewController,點(diǎn)擊Next按鈕,完成創(chuàng)建。
當(dāng)點(diǎn)擊BIDDisclosureButtonController上的disclosure button后,會(huì)轉(zhuǎn)到BIDDisclosureDetailController,顯示詳細(xì)內(nèi)容。
打開(kāi)BIDDisclosureDetailController.h,添加如下代碼
#import <UIKit/UIKit.h>@interface BIDDisclosureDetailController : UIViewController@property (strong, nonatomic) IBOutlet UILabel *label;@property (copy, nonatomic) NSString *message;@end
我們定義了一個(gè)outlet,用來(lái)指向UILabel,之后我們會(huì)添加一個(gè)xib,xib上會(huì)拖入一個(gè)Label控件,這個(gè)outlet就是指向xib上的Label控件的。我們還定義了一個(gè)NSString用于保存字符串,這個(gè)字符串會(huì)顯示在label上。
這里有一個(gè)問(wèn)題,為什么還需要另外定義一個(gè)message,而不是直接賦值誒label,這個(gè)是因?yàn)閁ILabel是xib上的一個(gè)控件,當(dāng)view沒(méi)有載入的時(shí)候,這個(gè)UILabel是不存在的,我們沒(méi)有辦法為其賦值,所以我們就暫時(shí)保存在一個(gè)變量中,然后當(dāng)xib載入后,再賦值給label,曲線(xiàn)救國(guó)嘛,
打開(kāi)BIDDisclosureDetailController.m,添加如下代碼
#import "BIDDisclosureDetailController.h"@implementation BIDDisclosureDetailController@synthesize label;@synthesize message;- (void)viewWillAppear:(BOOL)animated { label.text = message; [super viewWillAppear:animated];}- (void)viewDidUnload { self.label = nil; self.message = nil; [super viewDidUnload];}@end
注意,我們這里使用了viewWillAppear,而不是通常使用的viewDidLoad,viewDidLoad只有在第一次載入view的時(shí)候才會(huì)被調(diào)用到,如果這個(gè)view被反復(fù)的載入,那么之后的載入過(guò)程,viewDidLoad將不會(huì)被調(diào)用,而viewWillAppear則不用,每次view的載入,這個(gè)方法都會(huì)被調(diào)用到,在這里例子中,我們將多次載入xib,而且每次xib顯示的內(nèi)容會(huì)根據(jù)之前一個(gè)table view中cell的不同而不同,因此每次都需要更新內(nèi)容,所以在這種情況下,使用viewWillAppear是比較恰當(dāng)?shù)倪x擇。
選中Project navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,在彈出的窗口中,左邊選擇User Interface,右邊選擇View,點(diǎn)擊Next按鈕,Device Family選擇iphone,點(diǎn)擊Next按鈕,命名為BIDDisclosureDetail.xib,點(diǎn)擊Create按鈕,完成創(chuàng)建。
選擇Project navigator中的BIDDisclosureDetail.xib,然后點(diǎn)擊File's Owner,打開(kāi)Identity inspcetor,將Class指定為BIDDisclosureDetailController
然后control-drag File's Owner到Objects中的View上,在彈出的框中選擇view,完成關(guān)聯(lián)。
從Library中拖一個(gè)UILabel放在view的正中間,然后拉伸UILabel的寬度到左右兩邊,將label的文字對(duì)其方式設(shè)置為居中,然后control-drag File's Owner到label,在彈出的框中選擇label,完成關(guān)聯(lián)。
打開(kāi)BIDDisclosureButtonController.h,添加如下代碼
#import "BIDSecondLevelViewController.h"@interface BIDDisclosureButtonController : BIDSecondLevelViewController@property (strong, nonatomic) NSArray *list;@end
代碼中僅僅定義了一個(gè)NSArray,用于保存在table view中的每一行的內(nèi)容
打開(kāi)BIDDisclosureButtonController.m,添加如下代碼
#import "BIDDisclosureButtonController.h"#import "BIDAppDelegate.h"#import "BIDDisclosureDetailController.h"@interface BIDDisclosureButtonController() @property (strong, nonatomic) BIDDisclosureDetailController *childController;@end@implementation BIDDisclosureButtonController@synthesize list;@synthesize childController;- (void)viewDidLoad { [super viewDidLoad]; NSArray *array = [[NSArray alloc] initWithObjects:@"Toy Story", @"A Bug's Life", @"Toy Story 2", @"Monsters, Inc.", @"Finding Nemo", @"The Incredibles", @"Cars", @"Ratatouille", @"WALL-E", @"Up", @"Toy Story 3", @"Cars 2", @"Brave", nil]; self.list = array;}- (void)viewDidUnload { [super viewDidUnload]; self.list = nil; self.childController = nil;}#pragma mark -#pragma mark Table Data Source Methods- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *DisclosureButtonCellIdentifier = @"DisclosureButtonCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DisclosureButtonCellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DisclosureButtonCellIdentifier]; } NSUInteger row = [indexPath row]; NSString *rowString = [list objectAtIndex:row]; cell.textLabel.text = rowString; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; return cell;}#pragma mark -#pragma makr Table Delegate Methods- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hey, do you see the disclosure button?" message:@"If you're trying to drill down, touch that instead" delegate:nil cancelButtonTitle:@"Won't happen again" otherButtonTitles:nil]; [alert show];}- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { if (childController == nil) { childController = [[BIDDisclosureDetailController alloc] initWithNibName:@"BIDDisclosureDetail" bundle:nil]; } childController.title = @"Disclosure Button Pressed"; NSUInteger row = [indexPath row]; NSString *selectdMovie = [list objectAtIndex:row]; NSString *detailMessage = [[NSString alloc] initWithFormat:@"You pressed the disclosure button for %@.",selectdMovie]; childController.message = detailMessage; childController.title = selectdMovie; [self.navigationController pushViewController:childController animated:YES];}@end
代碼的開(kāi)頭有一個(gè)很少見(jiàn)的@interface,這是Objective-C的一種語(yǔ)法現(xiàn)象,用于對(duì)類(lèi)的擴(kuò)展,稱(chēng)之為class extension,意思是就某些情況下,單獨(dú)的對(duì)一個(gè)已存在的類(lèi)進(jìn)行擴(kuò)展(這里是添加了一個(gè)BIDDisclosureDetailController對(duì)象),而這個(gè)擴(kuò)展只對(duì)當(dāng)前類(lèi)有用,其他地方調(diào)用相同的類(lèi),里面不會(huì)有擴(kuò)展的內(nèi)容。(好吧,其實(shí)我也對(duì)Objective-C不是很熟悉,要詳細(xì)了解Objective-C大家還是找一本書(shū)看看比較好)
viewDidLoad中,創(chuàng)建了一個(gè)字符串?dāng)?shù)組,里面保存了table view中顯示的cell的內(nèi)容。
tableview:numberOfRowsInSection和tableView:cellForRowAtIndexPath都是很常見(jiàn)的實(shí)現(xiàn),和之前例子中的一樣。
tableView:didSelectRowAtIndexPath方法,當(dāng)點(diǎn)擊tableview的row時(shí),會(huì)調(diào)用該方法。
tableView:accessoryButtonTappedForRowWithIndexPath方法,當(dāng)點(diǎn)擊row右邊的disclosure button時(shí),會(huì)調(diào)用該方法。在該方法中,首先判斷childController是否被創(chuàng)建過(guò),如果沒(méi)有,就根據(jù)xib文件名創(chuàng)建一個(gè),之后的代碼應(yīng)該都可以讀懂是什么意思。
最后一步,修改BIDFirstLevelController,將BIDDisclosureButtonController添加進(jìn)去,打開(kāi)BIDFirstLevelController.m,添加如下代碼
#import "BIDFirstLevelController.h"#import "BIDSecondLevelViewController.h"#import "BIDDisclosureButtonController.h"......- (void)viewDidLoad { [super viewDidLoad]; self.title = @"First Level"; NSMutableArray *array = [[NSMutableArray alloc] init]; // Disclosure Button BIDDisclosureButtonController *disclosureButtonController = [[BIDDisclosureButtonController alloc] initWithStyle:UITableViewStylePlain]; disclosureButtonController.title = @"Disclosure Buttons"; disclosureButtonController.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"]; [array addObject:disclosureButtonController]; self.controllers = array;}
首先引入BIDDisclosureButtonController.h頭文件,然后在viewDidLoad方法中,創(chuàng)建一個(gè)BIDDisclosureButtonController對(duì)象,設(shè)置title和image,最后把它加入到array中,ok,我們第一個(gè)table view的操作到底結(jié)束,下面編譯運(yùn)行一下
程序運(yùn)行后的第一個(gè)畫(huà)面,多了一行cell,cell的最左邊是我們添加的rowImage,然后是下一個(gè)table view的title,最右邊是一個(gè)向右的箭頭,點(diǎn)擊第一個(gè)的cell,我們就進(jìn)入到與之對(duì)應(yīng)的下一個(gè)table view:BIDDisclosureButtonController
在navigator中顯示了當(dāng)前table view的title(整個(gè)title是在BIDFirstLevelController的viewDidLoad中設(shè)定的),navigator左邊的按鈕上顯示了上一層table view的title,表示點(diǎn)擊這個(gè)按鈕可以返回到哪一個(gè)table view。點(diǎn)擊table view中任意一個(gè)cell(不要點(diǎn)最右邊的圓圈箭頭按鈕,否則會(huì)切換到再下一層的table view),一個(gè)警告框彈出
這個(gè)就是調(diào)用了tableView:didSelectRowAtIndexPath方法,點(diǎn)擊最右邊的圓圈箭頭按鈕,轉(zhuǎn)到再下一層的table view(BIDDisclosureDetailController)
上面顯示了這個(gè)detail view的內(nèi)容
好了,整個(gè)的程序就是這樣,有點(diǎn)小小的復(fù)雜,不過(guò)如果你弄懂了其中的關(guān)系,實(shí)現(xiàn)起來(lái)還是不難的,不過(guò)需要很仔細(xì)。
6)第二個(gè)subtableview:The Checklist
這個(gè)例子相對(duì)簡(jiǎn)單一些,就是點(diǎn)擊table view中的cell,然后cell的右邊會(huì)出現(xiàn)一個(gè)對(duì)勾,表示選中的狀態(tài),當(dāng)選擇另一行的cell時(shí),這個(gè)對(duì)勾會(huì)出現(xiàn)在這一個(gè)cell上,而之前的對(duì)勾會(huì)消失。
好了,開(kāi)始工作,選中Project navigator中的Nav文件夾,單擊鼠標(biāo)右鍵,選擇“New File...”,在彈出的窗口中,左邊選擇Cocoa Touch,右邊選擇Objective-C class,點(diǎn)擊Next按鈕,在下一個(gè)窗口中將class命名為BIDCheckListController,Subclass of命名為BIDSecondLevelViewController,點(diǎn)擊Next按鈕,完成創(chuàng)建。
打開(kāi)BIDCheckListController.h,添加如下代碼
#import "BIDSecondLevelViewController.h"@interface BIDCheckListController : BIDSecondLevelViewController@property (strong, nonatomic) NSArray *list;@property (strong, nonatomic) NSIndexPath *lastIndexPath;@end
NSArray用于保存cells的內(nèi)容,由于我們只允許一行cell被選中,因此我們需要記錄上一次選中的是哪行cell,當(dāng)選擇新的一行cell時(shí),把上一次選中的cell的對(duì)勾去掉,創(chuàng)建一個(gè)NSIndexPath變量,用來(lái)保存最后一次選中的cell。
打開(kāi)BIDCheckListController.m,添加如下代碼
#import "BIDCheckListController.h"@implementation BIDCheckListController@synthesize list;@synthesize lastIndexPath;- (void)viewDidLoad { [super viewDidLoad]; NSArray *array = [[NSArray alloc] initWithObjects:@"Who Hash", @"Bubba Gump Shrimp Étouffée", @"Who Pudding", @"Scooby Snacks", @"Everlasting Gobstopper", @"Green Eggs and Ham", @"Soylent Green", @"Hard Tack", @"Lembas Bread", @"Roast Beast", @"Blancmange", nil]; self.list = array;}- (void)viewDidUnload { [super viewDidUnload]; self.list = nil; self.lastIndexPath = nil;}#pragma mark -#pragma mark Table Data Source Methods- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CheckMarkCellIdentifier = @"CheckMarkCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CheckMarkCellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CheckMarkCellIdentifier]; } NSUInteger row = [indexPath row]; NSUInteger oldRow = [lastIndexPath row]; cell.textLabel.text = [list objectAtIndex:row]; cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; return cell;}#pragma mark -#pragma mark Table Delegate Methods- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { int newRow = [indexPath row]; int oldRow = (lastIndexPath != nil) ? [lastIndexPath row] : -1; if(newRow != oldRow) { UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath]; newCell.accessoryType = UITableViewCellAccessoryCheckmark; UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:lastIndexPath]; oldCell.accessoryType = UITableViewCellAccessoryNone; lastIndexPath = indexPath; } [tableView deselectRowAtIndexPath:indexPath animated:YES];}@end
有幾個(gè)地方需要解釋一下
tableView:cellForRowAtIndexPath方法中:
cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
看選中的行和之前選中的行是否一樣而起lastIndexPath必須存在,這樣的話(huà),在新選中的行上顯示對(duì)勾,UITableViewCellAccessoryCheckmark會(huì)在cell上顯示對(duì)勾(我認(rèn)為這個(gè)判斷是在已經(jīng)選中過(guò)cell,然后選中navigator上的返回按鈕返回到上一層的view,之后在此進(jìn)入這個(gè)view的時(shí)候,做一個(gè)這樣的判斷,看看在view載入的時(shí)候,是否需要對(duì)某一個(gè)cell進(jìn)行選擇)
tableView:didSelectRowAtIndexPath方法,我覺(jué)得里面實(shí)現(xiàn)的方式還是很直觀的,直接讀代碼應(yīng)該可以看懂里面的意思。
最后一步,修改BIDFirstLevelController,將BIDCheckListController添加進(jìn)去,打開(kāi)BIDFirstLevelController.m,添加如下代碼
#import "BIDFirstLevelController.h"#import "BIDSecondLevelViewController.h"#import "BIDDisclosureButtonController.h"#import "BIDCheckListController.h"@implementation BIDFirstLevelController@synthesize controllers;- (void)viewDidLoad { [super viewDidLoad]; self.title = @"First Level"; NSMutableArray *array = [[NSMutableArray alloc] init]; // Disclosure Button BIDDisclosureButtonController *disclosureButtonController = [[BIDDisclosureButtonController alloc] initWithStyle:UITableViewStylePlain]; disclosureButtonController.title = @"Disclosure Buttons"; disclosureButtonController.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"]; [array addObject:disclosureButtonController]; //Checklist BIDCheckListController *checkListController = [[BIDCheckListController alloc] initWithStyle:UITableViewStylePlain]; checkListController.title = @"Check One"; checkListController.rowImage = [UIImage imageNamed:@"checkmarkControllerIcon.png"]; [array addObject:checkListController]; self.controllers = array;}
這個(gè)就不解釋了,和之前的一樣,編譯運(yùn)行程序
多了一行Check One,選中該行天轉(zhuǎn)到BIDCheckListController
隨便選哪一行,會(huì)有一個(gè)對(duì)勾出現(xiàn),如果選中另一行,對(duì)勾會(huì)出現(xiàn)在另一行上
7)未完待續(xù)
這篇就暫時(shí)到這里,我們還將添加其他3個(gè)subtableview,會(huì)在下一篇中進(jìn)行介紹,謝謝!
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注