IOS開發-表視圖LV3導航控制器


學到這裏感覺有點難了,其實這篇文章再草稿箱裏放了好久了~ 最近對於學習的熱情下降了。這不行~抓緊學習走起!


在這一章節的學習中主要針對導航控制器及表視圖來建立多視圖的應用,

首先要了解一些概念--

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版,分享給大家,大家也可以參考書中的例子來學習喔~

iPhone4與iPad開發基礎教程 英文原版PDF及源碼




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章