官术网_书友最值得收藏!

3.2 畫面跳轉(zhuǎn)

3.2.1 使用UITabBarController實(shí)現(xiàn)并列畫面跳轉(zhuǎn)

前一節(jié)介紹了由UIViewController實(shí)現(xiàn)的畫面切換。實(shí)際上并非真的實(shí)現(xiàn)了兩個(gè)畫面間的跳轉(zhuǎn),而是同時(shí)啟動(dòng)兩個(gè)畫面,控制其中哪一個(gè)畫面顯示在前臺(tái),哪一個(gè)畫面顯示在后臺(tái)而已。這種畫面跳轉(zhuǎn)方式有一個(gè)很大的缺點(diǎn),即當(dāng)畫面數(shù)量增加時(shí),畫面跳轉(zhuǎn)的實(shí)現(xiàn)代碼將越來(lái)越復(fù)雜,而且各個(gè)畫面間不可避免地有相互依賴關(guān)系。

實(shí)際上,在UIKit中提供了專用的管理畫面跳轉(zhuǎn)的類,這就是UITabBarController類以及UINavigationController類。本節(jié)首先介紹使用UITabBarController類如何實(shí)現(xiàn)畫面間的跳轉(zhuǎn)功能。

下面我們以上一節(jié)實(shí)例代碼為基礎(chǔ),將其改造成使用UITabBarController類來(lái)實(shí)現(xiàn)畫面間的跳轉(zhuǎn)。首先將HelloWorldAppDelegate改名為MultiViewAppDelegate,并進(jìn)行如下修改(代碼中粗體字部分)。

[MultiViewAppDelegate.h]
#import <UIKit/UIKit.h>
@interface MultiViewAppDelegate :NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UIViewController *rootController;
}
@property(nonatomic,retain)UIWindow *window;
@end
[MultiViewAppDelegate.m]
#import "MultiViewAppDelegate.h"
#import "ViewController1.h"
#import "ViewController2.h"
@implementation MultiViewAppDelegate
@synthesize window;
#pragma mark -
#pragma mark Application lifecycle
-(BOOL)application:(UIApplication *)application didFinishLaunchin gWithOptions:(NSDictionary *)launchOptions {
  // 初始化window實(shí)例變量
  CGRect frame = [[UIScreen mainScreen] bounds];
  self.window = [[UIWindow alloc] initWithFrame:frame];
  // 創(chuàng)建母體Controller實(shí)例
  rootController = [[UITabBarController alloc] init];
  // 創(chuàng)建畫面1與畫面2的Controller實(shí)例
  ViewController1 *tab1 = [[[ViewController1 alloc] init] autorelease];
  ViewController2 *tab2 = [[[ViewController2 alloc] init] autorelease];
  // 將畫面1、畫面2的Controller實(shí)例以數(shù)組的形式追加到母體Controller中
  NSArray *tabs = [NSArray arrayWithObjects:tab1,tab2,nil];
  [(UITabBarController)rootController setViewControllers:tabs animated:NO];
  // 將母體Controller的view追加到Window中
  [self.window addSubView:rootController.view];
    [self.window makeKeyAndVisible];
    return YES;
}
-(void)dealloc {
    [rootController release];
    [window release];
    [super dealloc];
}
@end

要修改的地方并不多。首先刪除前例中單獨(dú)創(chuàng)建兩個(gè)畫面的實(shí)例變量ViewControllerl以及ViewController2,取而代之的是UITabBarController類型的實(shí)例變量rootController。上例中將兩個(gè)畫面的view直接追加到Window中,本例中只需要將UITabBarController類型實(shí)例變量的view追加到Window中。而將兩個(gè)畫面的UIViewController對(duì)象以數(shù)組的形式追加到UITabBarController類型的實(shí)例變量中,此時(shí)調(diào)用了setViewControllers:animated:方法,此方法的第一個(gè)參數(shù)即為UIViewController對(duì)象數(shù)組。

接著,我們開始修改兩個(gè)畫面的實(shí)例代碼。其實(shí)施方法如下。

  • 按鈕去掉,刪除與按鈕相關(guān)的代碼。
  • 重寫(或稱覆蓋)init方法,其中追加與標(biāo)簽相關(guān)的代碼。

兩個(gè)畫面中的init方法的代碼如下。

[ViewController1.m]
-(id)init {
  if((self = [super init])){
    // 設(shè)置tabBar的相關(guān)屬性
    self.title = @"Hello";
    UIImage*icon = [UIImage imageNamed:@"ball1.png"];
    self.tabBarItem =
         [[[UITabBarItem alloc] initWithTitle:@"Hello" image:icon tag:0] autorelease];
  }
  return self;
}
[ViewController2.m]
-(id)init {
  if((self = [super init])){
    // 設(shè)置tabBar的相關(guān)屬性
    self.title = @"您好";
    UIImage*icon = [UIImage imageNamed:@"ball2.png"];
    self.tabBarItem =
       [[[UITabBarItem alloc] initWithTitle:@"您好" image:icon tag:0] autorelease];
  }
  return self;
}

重寫的init方法中也沒(méi)有追加多少內(nèi)容。設(shè)置title屬性后,導(dǎo)入圖標(biāo)用的圖片,并將其設(shè)置到UIViewController的 tabBarItem屬性中。調(diào)用initWithTitle:image:tag:方法進(jìn)行UITabBarItem類的初始化。第一個(gè)參數(shù)為標(biāo)簽條中顯示的標(biāo)題;第二個(gè)參數(shù)為指定顯示的圖標(biāo)圖片;第三個(gè)參數(shù)為標(biāo)簽的序號(hào),此序號(hào)通常用于程序內(nèi)檢索。

執(zhí)行這個(gè)經(jīng)過(guò)改造的工程后,將顯示如圖3-3所示的結(jié)果。

圖3-3 標(biāo)簽實(shí)現(xiàn)的畫面跳轉(zhuǎn)

3.2.2 使用UINavigationController實(shí)現(xiàn)多層畫面跳轉(zhuǎn)

iPhone4手機(jī)的自帶應(yīng)用程序中,既有使用UITabBarController來(lái)進(jìn)行畫面切換控制的,也有使用UINavigationController來(lái)實(shí)現(xiàn)多畫面間的跳轉(zhuǎn)的。例如iPod音樂(lè)播放界面就采用了UITabBarController來(lái)進(jìn)行畫面切換控制,而iPhone手機(jī)設(shè)置程序則采用了UINavigationController來(lái)實(shí)現(xiàn)多層次畫面間的跳轉(zhuǎn),圖3-4、圖3-5是這兩個(gè)程序部分畫面的跳轉(zhuǎn)示意圖。

圖3-4 iPod音樂(lè)播放程序畫面跳轉(zhuǎn)示意圖

與UITabBarController實(shí)現(xiàn)畫面并行切換形式不同,UINavigationController是實(shí)現(xiàn)畫面多層次跳轉(zhuǎn),也是其最大的特征。如圖3-5所示,畫面1-1可以跳轉(zhuǎn)至其下一層的畫面1-1-1以及畫面1-1-2中。另外UINavigationController可以自動(dòng)地記憶跳轉(zhuǎn)所經(jīng)過(guò)的路徑,按照這些記錄的路徑信息,可以依次返回到上層畫面中(即支持返回按鈕)。

圖3-5 iPhone設(shè)置程序部分畫面跳轉(zhuǎn)示意圖

下面我們將上一節(jié)采用UITabBarController實(shí)現(xiàn)的畫面切換程序,再一次改造成采用UINavigationController來(lái)實(shí)現(xiàn)畫面的跳轉(zhuǎn)程序。其中兩個(gè)下一層的畫面保持不變,在這之前我們還將追加一個(gè)主畫面,主畫面非常簡(jiǎn)單,只有一個(gè)iPhone表格視圖組成,兩個(gè)下層畫面的名稱依次顯示在表格中,當(dāng)單擊任何一個(gè)名稱時(shí)將會(huì)跳轉(zhuǎn)到對(duì)應(yīng)的下層畫面中,整個(gè)應(yīng)用程序的跳轉(zhuǎn)示意圖如圖3-6所示。

圖3-6 改造目標(biāo)程序的跳轉(zhuǎn)示意圖

要實(shí)現(xiàn)上述程序,首先要進(jìn)行如下兩處修改。

● 在HelloWorldAppDelegate.m中將基準(zhǔn)ViewController由UITableViewController替換為UINavigationController。

● 新追加主畫面的TopMenuController類。

需要注意一點(diǎn),這里我們對(duì)畫面1以及畫面2的實(shí)現(xiàn)代碼其實(shí)是沒(méi)有進(jìn)行任何修改的。只是留下了些原實(shí)例中追加的關(guān)于UITabBarController的注釋,請(qǐng)務(wù)必忽略。

下面我們看看HelloWorldAppDelegate.m的修改代碼,見代碼中的黑體字部分。

[HelloWorldAppDelegate.m]
#import "HelloWorldAppDelegate.h"
#import "TopMenuController.h"
@implementation HelloWorldAppDelegate
@synthesize window = window_;
-(void)applicationDidFinishLaunching:(UIApplication *)application {
  // 初始化Window實(shí)例變量
  CGRect bounds = [[UIScreen mainScreen] bounds];
  window_ = [[UIWindow alloc] initWithFrame:bounds];
  // 創(chuàng)建基準(zhǔn)的Controller對(duì)象
  TopMenuController*topMenu = [[[TopMenuController alloc] init] autorelease];
  rootController_ = [[UINavigationController alloc] initWithRootVi ewController:topMenu];
  // 將主畫面的view追加到Window中
  [window_ addSubview:rootController_.view];
  [window_ makeKeyAndVisible];
}
-(void)dealloc {
  [rootController_ release];
  [window_ release];
  [super dealloc];
}
@end

大家可以看到,其實(shí)只修改了其中三行代碼。首先需要導(dǎo)入 TopMenuController類,并創(chuàng)建其實(shí)例。接著初始化UINavigationController,需要向initWithRootViewController:方法中傳入根畫面的Controller,這里將創(chuàng)建好的TopMenuController實(shí)例傳入。然后將UINavigationController的view屬性追加到UIWindow中(使用addSubView:方法)。

下面是新追加的主菜單畫面TopMenuController的代碼。這里將TopMenuController以UITableViewController子類形式來(lái)創(chuàng)建。

[TopMenuController.h]
#import <UIKit/UIKit.h>
@interface TopMenuController :UITableViewController
{
 @private
  NSMutableArray* items_;
}
@end
[TopMenuController.m]
#import "TopMenuController.h"
@implementation TopMenuController
-(void)dealloc {
  [items_ release];
  [super dealloc];
}
-(id)init {
  if((self = [super initWithStyle:UITableViewStylePlain])){
    self.title = @"主菜單";
    //-------------------------------<1>
    // 創(chuàng)建顯示用數(shù)組
    items_ = [[NSMutableArray alloc] initWithObjects:
                  @"ViewController1",
                  @"ViewController2",
                  nil ];
  }
  return self;
}
#pragma mark ----- UITableViewDataSource Methods -----
-(NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
  return [items_ count];
}
-(UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  // 檢查單元是否已經(jīng)創(chuàng)建
  UITableViewCell* cell = [tableView dequeueReusableCellWithIdenti
fier:@"simple-cell"];
  if(!cell){
    // 沒(méi)有創(chuàng)建的單元新創(chuàng)建
    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:@"simple-cell"] autorelease];
  }
  // 設(shè)置單元中顯示的文本字符串
  cell.textLabel.text = [items_ objectAtIndex:indexPath.row];
  //------<2>
  return cell;
}
#pragma mark ----- UITableViewDelegate Methods ---------<3>
-(void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
  Class class = NSClassFromString([items_ objectAtIndex:indexPath.row]);
  id viewController = [[[class alloc] init] autorelease];
  if(viewController){[self.navigationController pushViewController:viewController animated:YES];
  }
}
@end

與表相關(guān)的解說(shuō)將放在第7章中,代碼中有不理解的地方,請(qǐng)參考第7章的相關(guān)介紹。首先看看init方法中的內(nèi)容。在titile屬性中設(shè)置畫面的標(biāo)題(<1>)。使用UINavigationController時(shí),此處設(shè)置的標(biāo)題將在畫面的最上方中心位置顯示(見圖3-7)。接著還創(chuàng)建了NSArray數(shù)組,NSArray數(shù)組中的元素將顯示在表中。具體處理在tableView:cellForRowAtIndexPath:方法中,將NSArray中的元素設(shè)置到表的單元中。

圖3-7 UINavigationController的標(biāo)題

其次,我們?cè)俅_認(rèn)一下tableView:didSelectRowAtIndexPath:方法的處理內(nèi)容。此方法將在表單元被觸摸(單擊)時(shí)調(diào)用,參數(shù)indexPath中保存了具體被觸摸(單擊)的行信息。

本例中,表單元中直接放置了跳轉(zhuǎn)對(duì)象畫面的類名,tableView:didSelectRow AtIndexPath:方法中首先創(chuàng)建被觸摸行類的實(shí)例。然后跳轉(zhuǎn)到對(duì)應(yīng)畫面中。調(diào)用UINavigationController的pushViewController:animated:方法實(shí)現(xiàn)畫面跳轉(zhuǎn);向此方法的第一個(gè)參數(shù)中傳入畫面(UIViewController)的實(shí)例后,然后就會(huì)自動(dòng)跳轉(zhuǎn)到對(duì)應(yīng)層次的畫面中。另外如果將animated參數(shù)設(shè)置為YES,則下一畫面將以動(dòng)畫的形式顯示出來(lái)。此時(shí)UINavigationController實(shí)例可以通過(guò)UIViewController的navigationController屬性獲取。只要是UINavigationController管理下的UIViewController,隨時(shí)都可以通過(guò)其navigationController屬性獲取UINavigationController實(shí)例本身。

這樣就算完成了整個(gè)層次的畫面跳轉(zhuǎn)應(yīng)用程序。跳轉(zhuǎn)到下一層畫面后,將自動(dòng)顯示如圖3-8所示的返回按鈕。

圖3-8 UINavigationController的返回按鈕

3.2.3 跳轉(zhuǎn)到任意畫面

上一小節(jié)中通過(guò)pushViewController:animated:方法能實(shí)現(xiàn)畫面的跳轉(zhuǎn),而且能在導(dǎo)航條上自動(dòng)追加返回上一畫面的返回按鈕。這種“返回到前一畫面”的功能正確的表述應(yīng)該為“返回到上一級(jí)”畫面,調(diào)用popViewControllerAnimation:方法也能實(shí)現(xiàn)同樣的功能。其他的如UINavigationController類還提供了直接返回到主畫面的popToRootViewControllerAnimation:方法,以及返回到任意一級(jí)畫面的popToViewController:animated:方法,以下是這三種方法的調(diào)用代碼。

// 返回到上一級(jí)畫面
[self.navigationController popViewControllerAnimation:Yes];
// 返回根畫面
[self.navigationController popToRootViewControllerAnimation:Yes];
// 返回任意指定畫面
[self.navigationController popToViewController:viewController animated:Yes];

另外,從iPhone OS 3.0以后,可以通過(guò)調(diào)用setViewController:animated:方法將畫面的跳轉(zhuǎn)歷史路徑(堆棧)完全替換。替換歷史路徑的示意圖如圖3-9所示。

圖3-9 替換歷史路徑

實(shí)現(xiàn)圖3-9所示的替換歷史路徑的代碼如下。

// 將跳轉(zhuǎn)歷史路徑替換為畫面1> 畫面1-3> 畫面1-3-1
id scene1 = [[[Scene alloc] init] autorelease];
// 創(chuàng)建畫面1的實(shí)例
id scene13 = [[[Scene3 alloc] init] autorelease];
// 創(chuàng)建畫面1-3的實(shí)例
id scene131 = [[[Scene31 alloc] init] autorelease];
// 創(chuàng)建畫面1-3-1的實(shí)例
NSArray *history = [NSArray arrayWithObjects:scene1,scene13,scene13 1,nil];
[self.navigationController setViewControllers:history animated:Yes];

popToViewController:animated:方法的第一個(gè)參數(shù)中必須傳入U(xiǎn)IViewController的實(shí)例,不是新創(chuàng)建的實(shí)例,而是實(shí)際跳轉(zhuǎn)過(guò)程中原畫面的實(shí)例。此時(shí),可以通過(guò)UINavigationController的viewControllers屬性來(lái)參照。viewControllers屬性中保存的正是NSArray形式的跳轉(zhuǎn)畫面實(shí)例集合。

調(diào)用setViewControllers:animated方法進(jìn)行跳轉(zhuǎn)畫面堆棧替換時(shí),也可以viewControllers屬性中保存的實(shí)例集合為基礎(chǔ),進(jìn)行部分UIViewController實(shí)例的替換。

3.2.4 模態(tài)(modal)畫面的顯示方法

PC桌面軟件中經(jīng)常可以看到如“文件讀取對(duì)話框”等模態(tài)對(duì)話框的畫面類型。這些畫面就顯示在主畫面的上方,當(dāng)對(duì)話框中的操作結(jié)束,關(guān)閉對(duì)話框畫面后將顯示原來(lái)的畫面,屬于一種臨時(shí)畫面。iPhone應(yīng)用程序中也能實(shí)現(xiàn)這種模態(tài)畫面,例如iPhone通信錄管理程序中,追加新的通信錄時(shí)也使用了這種模態(tài)畫面。

模態(tài)畫面沒(méi)有什么特別的地方,與其他畫面一樣也是由UIViewController的子類實(shí)現(xiàn)的畫面,只是調(diào)用的方式不同而已。以下是模態(tài)畫面顯示的調(diào)用方式以及顯示后關(guān)閉畫面的實(shí)例代碼。

// ModalDialog為UIViewController的子類
id dialog = [[[ModalDialog alloc] init] autorelease];
[self presentModalViewController:dialog animated:YES];
// 關(guān)閉模態(tài)UIViewController
[self dismissModalViewControllerAnimationed:YES];

如上述代碼所示,將UIViewController子類的實(shí)例作為presentModalViewController:animated:方法的第一個(gè)參數(shù)進(jìn)行調(diào)用后,就能實(shí)現(xiàn)以模態(tài)方式顯示畫面。關(guān)閉時(shí)調(diào)用dismissModalViewControllerAnimationed:方法。模態(tài)畫面調(diào)用后的示意圖如圖3-10所示。

圖3-10 模態(tài)畫面顯示示意圖

從iPhone OS 3.0開始,追加了設(shè)置模態(tài)畫面顯示/隱藏時(shí)動(dòng)畫效果的modalTranstionStyle屬性,可設(shè)置三種不同的值,分別如下。

● UIModalTransitionStyleCoverVertical:畫面從下向上徐徐彈出,關(guān)閉時(shí)向下隱藏(默認(rèn)方式)。

● UIModalTransitionStyleFlipHorizontal:從前一個(gè)畫面的后方,以水平旋轉(zhuǎn)的方式顯示后一畫面。

● UIModalTransitionStyleCrossDissolve:前一畫面逐漸消失的同時(shí),后一畫面逐漸顯示。

以下是圖3-10所示模態(tài)畫面的代碼,僅供參考。大家可以看到,其與普通的UIViewController子類沒(méi)有任何區(qū)別。

// 以模態(tài)形式顯示的畫面
// 內(nèi)容與普通畫面一樣
@interface ModalDialog :UIViewController
@end
@implementation ModalDialog
-(void)viewDidLoad {
  [super viewDidLoad];
  // 追加1個(gè)標(biāo)簽
  UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
  label.backgroundColor = [UIColor blackColor];
  label.textColor = [UIColor whiteColor];
  label.textAlignment = UITextAlignmentCenter;
  label.text = @"您好。我是模態(tài)畫面。";
  [self.view addSubview:label];
  // 追加關(guān)閉按鈕
  UIButton* goodbyeButton = [UIButton buttonWithType:UIButtonTypeR oundedRect];
  [goodbyeButton setTitle:@"Good-bye" forState:UIControlStateNormal];
  [goodbyeButton sizeToFit];
  CGPoint newPoint = self.view.center;
  newPoint.y += 80;
  goodbyeButton.center = newPoint;
  [goodbyeButton addTarget:self
                    action:@selector(goodbyeDidPush)
          forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:goodbyeButton];
}
-(void)goodbyeDidPush {
  // 關(guān)閉模態(tài)對(duì)話框
  [self dismissModalViewControllerAnimated:YES];
}
@end
主站蜘蛛池模板: 乌兰浩特市| 苏州市| 阿城市| 宾川县| 德州市| 宽甸| 清丰县| 蒙自县| 苏尼特右旗| 保山市| 买车| 合江县| 高雄县| 宁安市| 铅山县| 会同县| 揭阳市| 潜江市| 林芝县| 安多县| 宽城| 唐山市| 元江| 东丽区| 华池县| 那曲县| 丹江口市| 阿瓦提县| 张家口市| 巴彦淖尔市| 喀喇沁旗| 巨鹿县| 阳朔县| 巫溪县| 乌兰察布市| 嘉义市| 安阳县| 鹿泉市| 自贡市| 新沂市| 鄂温|