学到这里感觉有点难了,其实这篇文章再草稿箱里放了好久了~ 最近对于学习的热情下降了。这不行~抓紧学习走起!
在这一章节的学习中主要针对导航控制器及表视图来建立多视图的应用,
首先要了解一些概念--
1.导航控制器
UINavigationController是用于构建分层应用程序的主要工具,它在管理以及换入和换出多个内容视图方面与UITabBarController较为类似。
两者间的不动之处在于UINavigationController是作为栈来实现,这让他非常适用于处理分层的数据。栈:先进后出,后进先出。
2.控制器栈
根控制器(root view controller) 子控制器(subcontroller)
在设计导航控制器时,需要指定用户看到的第一个视图,该视图处在导航栈的最底层,其对应的控制器称为根控制器.所以不要把根控制器理解为导航控制器.根控制器也是导航控制器的一个子控制器.
在术语上把栈中的除了根控制器其余的控制器称为子控制器.
一般地,根控制器对应的视图上有各个子控制器视图的入口,回退到根视图然后再切换各个子视图.
默认地,导航控制器会自动在当前子控制器对应视图的导航栏的右端加一个返回按钮,名称是上一个视图的标题.
3. 导航按钮.
导航按钮类似于网页上的后退按钮,当点击时,当前的视图控制器出栈,栈中的下一个视图成为当前视图.
4. 其它术语:
扩展图标(accessory icon)称为扩展指示器(disclosure indicator),告知将切换到另一个视图,它以一个灰色箭头表示.
细节展示按钮(detail disclosure button)不仅是一个图标,它还是一个可单击的控件.
实例:
下面将建立一个由6个部分组成的分层应用程序:NavNice
主视图如下:
即有6子控制器
第一个子控制器是展示按钮视图 包含一个细节展示按钮
第二个子控制器是校验表视图 “多选一”的操作
第三个子控制器是行控制视图 在每行的扩展视图中添加了一个可单击的按钮
第四个子控制器是可移动行视图 可以对行进行重新排序
第五个子控制器是可删除行视图 允许删除行的编辑模式
第六个子控制器是可编辑详细信息视图 对详细信息的编辑模式 - 这里的编码可能有点问题~
1.首先,建立一个空项目。从零开始。
然后,建立FirstLevelViewController 及 SecondLevelViewController ,
在建文件的同时让它们继承于UITableViewCell,XCode会帮我们自动实现协议抽象方法
现在项目的骨架如下:
2.下一步,在AppDelegate.m中启用委托加载视图
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // // Override point for customization after application launch. // self.window.backgroundColor = [UIColor whiteColor]; // [self.window makeKeyAndVisible]; // return YES; self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. FirstLevelViewController *first = [[FirstLevelViewController alloc] init]; UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:first]; self.window.rootViewController = navigation; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
3.启动运行,一级页面效果 效果如下: 空空白白就一个tableView
4.接下来要编写第一个子控制器的内容,由于它还嵌套了另一个视图,所以这里先从里到外从详情页写起。
建立DisclosureDetailViewController及DisclosureDetail.xib
DisclosureDetailViewController.h编码
#import <UIKit/UIKit.h> @interface DisclosureDetailViewController : UIViewController @property (retain, nonatomic) IBOutlet UILabel *label; @property (copy, nonatomic) NSString *message; @end
DisclosureDetailViewController.m相关编码
@synthesize label;
@synthesize message;
- (void)viewWillAppear:(BOOL)animated; { [super viewWillAppear:animated]; self.label.text = self.message; } -(void) dealloc { [label release]; [message release]; [super dealloc]; }
在DisclosureDetail.xib上放一个label 把DisclosureDetail.xib的View及label 与DisclosureDetailViewController关联起来。
5.修改展示按钮控制器,建立按钮视图
这里需要建立第一个子控制来指向刚才构建的DisclosureDetailViewController
#import "SecondLevelViewController.h" @class DisclosureDetailViewController; @interface DisclosureButtonViewController : SecondLevelViewController @property (nonatomic,retain) NSArray *list; @property (nonatomic,retain) DisclosureDetailViewController *childController; @end
.m文件关键代码
//加载数据 - (void)viewDidLoad { NSArray *array =[[NSArray alloc]initWithObjects:@"toy story",@"a bug's life",@"toy story1",@"jay", @"toy story2",@"hacker",@"toy story3",@"1326", @"toy story4",@"coding", nil]; self.list = array; [array release]; [super viewDidLoad]; // Do any additional setup after loading the view. } //释放销毁对象 -(void)dealloc { [list release]; [childController release]; [super dealloc]; } //返回行数 -(NSInteger) tableView :(UITableViewCell*) tableview numberOfRowsInSection:(NSInteger)section { return [list count]; } //绑定每行数据 -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *DisclocsutreButtonCellIdetifier = @"DisclosutreButtonCellIdetifier"; UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:DisclocsutreButtonCellIdetifier]; if(cell ==nil) { cell =[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DisclocsutreButtonCellIdetifier]autorelease]; } NSUInteger row = [indexPath row]; NSString *rowString = [list objectAtIndex:row]; cell.textLabel.text = rowString; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; [rowString release]; return cell; } //处理不选中事件 这里要区别Deselect与Select -(void) tableView:(UITableView*)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { UIAlertView *alert = [[UIAlertView alloc ]initWithTitle:@"Hey,Man" message:@"drill down,touch that instead" delegate:nil cancelButtonTitle:@"Won't happen again" otherButtonTitles:nil]; [alert show]; [alert release]; } //展示按钮方法 -(void) tableView:(UITableView*)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { if(childController ==nil) { childController = [[DisclosureDetailViewController alloc]initWithNibName:@"DisclosureDetail" bundle:nil]; } childController.title = @"Disclosure Button Pressed"; NSUInteger row = [indexPath row]; NSString *selectMovie=[list objectAtIndex:row]; NSString *detailMessage = [[NSString alloc]initWithFormat:@"You pressed the disclosure button for %@.",selectMovie]; childController.message = detailMessage; childController.title = selectMovie; [detailMessage release]; [self.navigationController pushViewController:childController animated:YES];//将详情视图推入控制器栈 }
6.回到FirstLevelViewController.m为Disclosure及其附属视图添加一个按钮控制器实例
关键代码:
- (void)viewDidLoad { self.title =@"Frist Level 1326"; NSMutableArray *array = [[NSMutableArray alloc]init]; DisclosureButtonViewController *disclosureButtonController = [[DisclosureButtonViewController alloc] initWithStyle:UITableViewStylePlain]; disclosureButtonController.title = @"Disclosure Buttons"; disclosureButtonController.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"]; [array addObject:disclosureButtonController]; [disclosureButtonController release]; self.controllers = array; [array release]; [super viewDidLoad]; }
当然,也要实现tableView的数据加载的三个方法及相关头文件引入。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return [self.controllers count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"FristLevelCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell ==nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease]; } SecondLevelViewController *controller = self.controllers[indexPath.row]; cell.textLabel.text = controller.title; cell.imageView.image = controller.rowImage; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; // Configure the cell... return cell; }
编译运行,效果如下:
添加第一个二级控制器之后的应用程序。
展示按钮视图
点击行视图
详细信息视图
通过4-6步骤的编码,就初步完成NavNice这个实例的1/6的工程,也看到多视图应用小小的成果。这看起来灰常的NICE~
7.第二个子控制器:校验表
依旧是建表视图,依旧是继承于SecondLevelViewController
#import "SecondLevelViewController.h" @interface CheckListViewController : SecondLevelViewController @property (nonatomic,retain) NSArray *list; @property (nonatomic,retain) NSIndexPath *lastIndexPath; @end
.m文件关键代码:
//数据初始化 - (void)viewDidLoad { NSArray *array = [[NSArray alloc]initWithObjects:@"hi,man1326",@"4y",@"viewDidLoad",@"dealloc",@"fristblood", @"double kill",@"nice",@"...",@"okokok",nil]; self.list = array; [array release]; [super viewDidLoad]; // Do any additional setup after loading the view. } //释放资源 -(void) dealloc { [list release]; [lastIndexPath release]; [super dealloc]; } -(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]autorelease]; } //从这个单元和当前选项提取行 NSUInteger row = [indexPath row]; NSUInteger oldRow = [lastIndexPath row]; cell.textLabel.text = [list objectAtIndex:row];//将它分配给单元的标题 cell.accessoryType = (row==oldRow&&lastIndexPath!=nil)? UITableViewCellAccessoryCheckmark:UITableViewCellAccessoryNone;//如果选中则设图标 否则不显示任何东西 return cell; } -(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;
self.lastIndexPath = indexPath;
} [tableView deselectRowAtIndexPath:indexPath animated:YES];//告诉表视图取消选中不凸显 }
8.添加校验表到控制器实例
在FirstLevelViewController.m添加CheckListController的索引表视图
- (void)viewDidLoad { self.title =@"Frist Level 1326"; NSMutableArray *array = [[NSMutableArray alloc]init]; //Disclosure Button DisclosureButtonViewController *disclosureButtonController = [[DisclosureButtonViewController alloc] initWithStyle:UITableViewStylePlain]; disclosureButtonController.title = @"Disclosure Buttons"; disclosureButtonController.rowImage = [UIImage imageNamed:@"disclosureButtonControllerIcon.png"]; [array addObject:disclosureButtonController]; [disclosureButtonController release]; //Checklist CheckListViewController *checkListController = [[CheckListViewController alloc]initWithStyle:UITableViewStylePlain]; checkListController.title = @"check one"; checkListController.rowImage = [UIImage imageNamed:@"checkmarkControllerIcon.png"]; [array addObject:checkListController]; [checkListController release]; self.controllers = array; [array release]; [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; }
编译运行,效果如下:
两行控制器,两行信息
点入check one页面
选中状态
9.第三个子控制器:行上的控件
依旧是建表视图,依旧是继承于SecondLevelViewController,这次命名为RowControlsController
RowControlsController.h文件代码
#import "SecondLevelViewController.h" @interface RowControlsController : SecondLevelViewController @property(nonatomic,retain)NSArray *list; -(IBAction)buttonTapped:(id)sender; @end
RowControlsController.m文件核心代码
-(IBAction)buttonTapped:(id)sender { UIButton *senderButton = (UIButton *)sender; UITableViewCell *buttonCell = (UITableViewCell*)[senderButton superview]; NSUInteger buttonRow = [[self.tableView indexPathForCell:buttonCell] row]; NSString *buttonTitle = [list objectAtIndex:buttonRow]; UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"You tapped the button" message:[NSString stringWithFormat:@"You tapped the button for %@",buttonTitle] delegate:nil cancelButtonTitle:@"ok" otherButtonTitles: nil]; [alert show]; [alert release]; } - (void)viewDidLoad { NSArray *array = [[NSArray alloc] initWithObjects:@"1326",@"1234",@"byebye",@"fouce",@"table",@"nice",@"good luck",@"48road",@"ganker", nil]; self.list = array; [array release]; [super viewDidLoad]; // Do any additional setup after loading the view. } -(void)dealloc { [list release]; [super dealloc]; } -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count]; } //数据源 -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * ControlRowIdentifier = @"ControlRowIdentifier"; UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:ControlRowIdentifier]; if(cell ==nil) { cell =[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ControlRowIdentifier]; UIImage *buttonUpImage=[UIImage imageNamed:@"button_up.png"]; UIImage *buttonDownImage = [UIImage imageNamed:@"button_down.png"]; UIButton *button=[UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(0.0, 0.0, buttonUpImage.size.width, buttonUpImage.size.height); [button setBackgroundImage:buttonUpImage forState:UIControlStateNormal]; [button setBackgroundImage:buttonDownImage forState:UIControlStateHighlighted]; [button setTitle:@"Tag" forState:UIControlStateNormal]; [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];//注册事件 cell.accessoryView= button; } NSUInteger row = [indexPath row]; NSString *rowTitle =[list objectAtIndex:row]; cell.textLabel.text= rowTitle; return cell; } //选中行委托 -(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger row = [indexPath row]; NSString *rowTitle =[list objectAtIndex:row]; UIAlertView *alert =[[UIAlertView alloc] initWithTitle:@"you tapped the row" message:[NSString stringWithFormat:@"you tapped %@",rowTitle] delegate:nil cancelButtonTitle:@"ok" otherButtonTitles: nil]; [alert show]; [alert release]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; }
10. 在主程序中添加行控件控制器的实例
回到FristLevelViewController,修改ViewDidLoad方法,在中间初始化数据插入关键代码
//Table row RowControlsController *rowController = [[RowControlsController alloc]initWithStyle:UITableViewStylePlain]; rowController.title = @"Row Controls"; rowController.rowImage = [UIImage imageNamed:@"rowControlsIcon"]; [array addObject:rowController]; [rowController release];
OK,编译执行,效果如下:
初始化画面-多了行控件的子控制器
点进二级控制器后的界面:
选中行中按钮是弹出的消息窗口
选中行时弹出的提示-
11.第四个控制器-可移动的行
要建立可移动的行,可以使用表视图的setEditing:animated:方法打开编辑模式,这个方法带两个BOOLEAN类型的参数,第一个指示编辑模式是否被打开,第二个指示表是否进行动画转换~打开编辑模式后,大量的新委托方法就开始发挥作用,如询问某一行是否可以被编辑或移除,并告知用户是否移除或编辑特定行。
下面,依旧是建表视图,继承SecondLevelViewController,这次命名为MoveMeController。
.h
#import "SecondLevelViewController.h" @interface MoveMeController : SecondLevelViewController @property (nonatomic,retain)NSMutableArray *list; -(IBAction) toggleMove; @end
.m关键代码
//操作方法 -(IBAction)toggleMove { [self.tableView setEditing:!self.tableView.editing animated:YES]; if(self.tableView.editing) { [self.navigationItem.rightBarButtonItem setTitle:@"Done"]; } else { [self.navigationItem.rightBarButtonItem setTitle:@"Move"]; } } - (void)viewDidLoad { if(list==nil){ NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"1623",@"y2ok",@"even",@"qazwsx",@"by",@"fly",@"boom",nil]; self.list=array; [array release]; } //初始化按钮 UIBarButtonItem *moveBtn = [[UIBarButtonItem alloc]initWithTitle:@"Move" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleMove)]; self.navigationItem .rightBarButtonItem = moveBtn; [moveBtn release]; [super viewDidLoad]; // Do any additional setup after loading the view. } -(void)dealloc { [list release]; [super dealloc]; } -(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count]; } -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *MoveMeCellIdentifier = @"MoveMeCellIdentifier"; UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:MoveMeCellIdentifier]; if(cell==nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MoveMeCellIdentifier]autorelease]; cell.showsReorderControl = YES;//启用编辑模式需要设置为yes } NSUInteger row = [indexPath row]; cell.textLabel.text = [list objectAtIndex:row]; return cell; } -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewCellEditingStyleNone; } -(BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return YES; } -(void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { NSUInteger fromRow = [sourceIndexPath row]; NSUInteger toRow = [destinationIndexPath row]; id object = [[list objectAtIndex:fromRow] retain]; [list removeObjectAtIndex:fromRow]; [list insertObject:object atIndex:toRow]; [object release]; }
12. 在主程序中添加换行控件控制器的实例
//move cell MoveMeController *moveMeConroller = [[MoveMeController alloc] initWithStyle:UITableViewStylePlain]; moveMeConroller.title=@"Move Me"; moveMeConroller.rowImage =[UIImage imageNamed:@"moveMeIcon.png"]; [array addObject:moveMeConroller]; [moveMeConroller release];
编译,运行效果:
一级页面:
二级页面:
点击Move
换行:
13.第五个子控制器-可删除的行
在启用表哥编辑模式后,可以对行进行移动调整,同样的可以可以对行进行删除。
依旧是建视图…
.h
#import "SecondLevelViewController.h" @interface DeleteMeController : SecondLevelViewController @property (nonatomic,retain) NSMutableArray *list; -(IBAction)toggleEdit:(id)sender; @end
.m关键代码
-(IBAction)toggleEdit:(id)sender { [self.tableView setEditing:!self.tableView.editing animated:YES]; if(self.tableView.editing) { [self.navigationItem.rightBarButtonItem setTitle:@"Done"]; } else { [self.navigationItem.rightBarButtonItem setTitle:@"Delete"]; } } - (void)viewDidLoad { if(list==nil) { NSString *path = [[NSBundle mainBundle]pathForResource:@"computers" ofType:@"plist"]; NSMutableArray *array = [[NSMutableArray alloc]initWithContentsOfFile:path]; self.list = array; [array release]; } UIBarButtonItem *editBtn = [[UIBarButtonItem alloc ]initWithTitle:@"Delete" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleEdit:)];//这里多了个: 是因为这个切换方法多了一个sender self.navigationItem.rightBarButtonItem = editBtn; [editBtn release]; [super viewDidLoad]; // Do any additional setup after loading the view. } -(NSInteger ) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [list count ]; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *DeleteMeCellIdentifier = @"DeleteMeCekkIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DeleteMeCellIdentifier]; if(cell ==nil) { cell =[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DeleteMeCellIdentifier] autorelease]; } NSInteger row = [indexPath row]; cell.textLabel.text = [self.list objectAtIndex:row]; return cell; } -(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { [self.list removeObjectAtIndex: [indexPath row]]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];//最终指定动画 渐渐隐退 }
14.依旧是在1级控制器中添加删除行的子控制器
打开FirstLevelViewController.h在 viewDidLoad中添加代码
//Delete Me DeleteMeController *deleteMeController = [[DeleteMeController alloc]initWithStyle:UITableViewStylePlain]; deleteMeController.title = @"Delete Me"; deleteMeController.rowImage = [UIImage imageNamed:@"deleteMeIcon.png"]; [array addObject:deleteMeController]; [deleteMeController release]; self.controllers = array;
编译执行,效果如下:
主页面
子控制器页面
可编辑状态页面
按左边按钮之后出现的删除按钮
15.第六个子控制器-可编辑的详情页实现
15.1.由于详情页的字内容来自于一个归档好的文件,这里需要先建一个实现<NSCoding>的协议来操作这个文件。
President源码如下
#import "SecondLevelViewController.h" #define kPresidentNumberKey @"President" #define kPresidentNameKey @"Name" #define kPresidentToKey @"ToYear" #define kPresidentFromKey @"FromYear" #define kPresidentPartyKey @"Party" @interface President : NSObject { int number; NSString *name; NSString *fromYear; NSString *toYear; NSString *party; } @property int number ; @property (nonatomic,copy) NSString *name; @property (nonatomic,copy) NSString *fromYear; @property (nonatomic,copy) NSString *toYear; @property (nonatomic,copy) NSString *party; @end
#import "President.h" @interface President () @end @implementation President @synthesize number; @synthesize name; @synthesize fromYear; @synthesize toYear; @synthesize party; -(void) dealloc { [name release]; [fromYear release]; [toYear release]; [party release]; [super dealloc]; } //把对象编码为归档文件 -(void)encodeWithCoder:(NSCoder *)coder { [coder encodeInt:self.number forKey:kPresidentNumberKey]; [coder encodeObject:self.name forKey:kPresidentNameKey]; [coder encodeObject:self.fromYear forKey:kPresidentFromKey]; [coder encodeObject:self.toYear forKey:kPresidentToKey]; [coder encodeObject:self.party forKey:kPresidentPartyKey]; } //从归档文件创建出对象 -(id)initWithCoder:(NSCoder *)coder { if(self=[super init]) { number =[coder decodeIntForKey:kPresidentNumberKey]; name = [[coder decodeObjectForKey:kPresidentNumberKey] retain]; fromYear = [[coder decodeObjectForKey:kPresidentFromKey] retain]; toYear = [[coder decodeObjectForKey:kPresidentToKey] retain]; party = [[coder decodeObjectForKey:kPresidentPartyKey] retain]; } return self; } @end
15.2.接下来创建视图列表
PresidentViewController 源码如下
.h关键代码
#import "SecondLevelViewController.h" @interface PresidentViewController : SecondLevelViewController { NSMutableArray *list; } @property (nonatomic,retain) NSMutableArray *list; @end
.m关键代码
//初始化 - (void)viewDidLoad { NSString *path = [[NSBundle mainBundle] pathForResource:@"Presidents" ofType:@"plist"]; NSData *data; NSKeyedUnarchiver *unarchiver; data = [[NSData alloc] initWithContentsOfFile:path]; unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; NSMutableArray *array = [unarchiver decodeObjectForKey:@"Presidents"]; self.list = array; [unarchiver finishDecoding]; [unarchiver release]; [data release]; [super viewDidLoad]; } //父视图会重新加载数据 - (void)viewWillAppear:(BOOL)animated { [self.tableView reloadData]; [super viewWillAppear:animated]; } //销毁 - (void)dealloc { [list release]; [super dealloc]; } #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 *PresidentListCellIdentifier = @"PresidentListCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PresidentListCellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:PresidentListCellIdentifier] autorelease]; } NSUInteger row = [indexPath row]; President *thePres = [self.list objectAtIndex:row]; cell.textLabel.text = thePres.name; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ - %@", thePres.fromYear, thePres.toYear]; return cell; } #pragma mark - #pragma mark Table Delegate Methods - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger row = [indexPath row]; President *prez = [self.list objectAtIndex:row]; PresidentDetailController *childController = [[PresidentDetailController alloc] initWithStyle:UITableViewStyleGrouped]; childController.title = prez.name; childController.president = prez; [self.navigationController pushViewController:childController animated:YES]; [childController release]; }
15.3.视图详情页的视图
PresidentDetailController
.h文件详情 这里实现了一个TextField的委托它和tableView的数据源委托原理差不多
#import <UIKit/UIKit.h> @class President; #define kNumberOfEditableRows 4 #define kNameRowIndex 0 #define kFromYearRowIndex 1 #define kToYearRowIndex 2 #define kPartyIndex 3 #define kLabelTag 4096 @interface PresidentDetailController : UITableViewController<UITextFieldDelegate> { President *president; NSArray *fieldLabels; NSMutableDictionary *tempValues; UITextField *textFieldBeingEdited; } @property (nonatomic, retain) President *president; @property (nonatomic, retain) NSArray *fieldLabels; @property (nonatomic, retain) NSMutableDictionary *tempValues; @property (nonatomic, retain) UITextField *textFieldBeingEdited; - (IBAction)cancel:(id)sender; - (IBAction)save:(id)sender; - (IBAction)textFieldDone:(id)sender; @end
.m文件关键代码
- (IBAction)cancel:(id)sender { [self.navigationController popViewControllerAnimated:YES]; } - (IBAction)save:(id)sender { if (textFieldBeingEdited != nil) { NSNumber *tagAsNum= [[NSNumber alloc] initWithInt:textFieldBeingEdited.tag]; [tempValues setObject:textFieldBeingEdited.text forKey: tagAsNum]; [tagAsNum release]; } for (NSNumber *key in [tempValues allKeys]) { switch ([key intValue]) { case kNameRowIndex: president.name = [tempValues objectForKey:key]; break; case kFromYearRowIndex: president.fromYear = [tempValues objectForKey:key]; break; case kToYearRowIndex: president.toYear = [tempValues objectForKey:key];break; case kPartyIndex: president.party = [tempValues objectForKey:key]; default: break; } } [self.navigationController popViewControllerAnimated:YES]; NSArray *allControllers = self.navigationController.viewControllers; UITableViewController *parent = [allControllers lastObject]; [parent.tableView reloadData]; } - (IBAction)textFieldDone:(id)sender { [sender resignFirstResponder]; } #pragma mark - - (void)viewDidLoad { NSArray *array = [[NSArray alloc] initWithObjects:@"Name:", @"From:", @"To:", @"Party:", nil]; self.fieldLabels = array; [array release]; UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(cancel:)]; self.navigationItem.leftBarButtonItem = cancelButton; [cancelButton release]; UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save:)]; self.navigationItem.rightBarButtonItem = saveButton; [saveButton release]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; self.tempValues = dict; [dict release]; [super viewDidLoad]; } - (void)dealloc { [president release]; [fieldLabels release]; [tempValues release]; [textFieldBeingEdited release]; [super dealloc]; } #pragma mark - #pragma mark Table Data Source Methods - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return kNumberOfEditableRows; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *PresidentCellIdentifier = @"PresidentCellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: PresidentCellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PresidentCellIdentifier] autorelease]; UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake(10, 10, 75, 25)]; label.textAlignment = UITextAlignmentRight; label.tag = kLabelTag; label.font = [UIFont boldSystemFontOfSize:14]; [cell.contentView addSubview:label]; [label release]; UITextField *textField = [[UITextField alloc] initWithFrame: CGRectMake(90, 12, 200, 25)]; textField.clearsOnBeginEditing = NO; [textField setDelegate:self]; textField.returnKeyType = UIReturnKeyDone; [textField addTarget:self action:@selector(textFieldDone:) forControlEvents:UIControlEventEditingDidEndOnExit]; [cell.contentView addSubview:textField]; } NSUInteger row = [indexPath row]; UILabel *label = (UILabel *)[cell viewWithTag:kLabelTag]; UITextField *textField = nil; for (UIView *oneView in cell.contentView.subviews) { if ([oneView isMemberOfClass:[UITextField class]]) textField = (UITextField *)oneView; } label.text = [fieldLabels objectAtIndex:row]; NSNumber *rowAsNum = [[NSNumber alloc] initWithInt:row]; switch (row) { case kNameRowIndex: if ([[tempValues allKeys] containsObject:rowAsNum]) textField.text = [tempValues objectForKey:rowAsNum]; else textField.text = president.name; break; case kFromYearRowIndex: if ([[tempValues allKeys] containsObject:rowAsNum]) textField.text = [tempValues objectForKey:rowAsNum]; else textField.text = president.fromYear; break; case kToYearRowIndex: if ([[tempValues allKeys] containsObject:rowAsNum]) textField.text = [tempValues objectForKey:rowAsNum]; else textField.text = president.toYear; break; case kPartyIndex: if ([[tempValues allKeys] containsObject:rowAsNum]) textField.text = [tempValues objectForKey:rowAsNum]; else textField.text = president.party; default: break; } if (textFieldBeingEdited == textField) { textFieldBeingEdited = nil; } textField.tag = row; [rowAsNum release]; return cell; } #pragma mark - #pragma mark Table Delegate Methods - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { return nil; } #pragma mark Text Field Delegate Methods - (void)textFieldDidBeginEditing:(UITextField *)textField { self.textFieldBeingEdited = textField; } - (void)textFieldDidEndEditing:(UITextField *)textField { NSNumber *tagAsNum = [[NSNumber alloc] initWithInt:textField.tag]; [tempValues setObject:textField.text forKey:tagAsNum]; [tagAsNum release]; }
15.4.把视图列表添加到第二级的控制器中
在FristLevel下添加代码
// President View/Edit PresidentViewController *presidentViewController = [[PresidentViewController alloc] initWithStyle:UITableViewStylePlain]; presidentViewController.title = @"Detail Edit"; presidentViewController.rowImage = [UIImage imageNamed:@"detailEditIcon.png"]; [array addObject:presidentViewController]; [presidentViewController release];
那么这样就把最后一个子控制器也添加进一级控制器了。
好啦,编码任务完成~~~
------------------------源码-----------------------
在这个Nav的练习中学到很多关于导航控制器的东西,多视图应用离不开这个,所以回头还得多多研究下~
文章的最后是一个福利时间,对于表视图及导航的学习主要通过一本开发书籍去系统学习的,
这是在网上找到的英文PDF版,分享给大家,大家也可以参考书中的例子来学习喔~