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

3.2 畫面跳轉

3.2.1 使用UITabBarController實現并列畫面跳轉

前一節介紹了由UIViewController實現的畫面切換。實際上并非真的實現了兩個畫面間的跳轉,而是同時啟動兩個畫面,控制其中哪一個畫面顯示在前臺,哪一個畫面顯示在后臺而已。這種畫面跳轉方式有一個很大的缺點,即當畫面數量增加時,畫面跳轉的實現代碼將越來越復雜,而且各個畫面間不可避免地有相互依賴關系。

實際上,在UIKit中提供了專用的管理畫面跳轉的類,這就是UITabBarController類以及UINavigationController類。本節首先介紹使用UITabBarController類如何實現畫面間的跳轉功能。

下面我們以上一節實例代碼為基礎,將其改造成使用UITabBarController類來實現畫面間的跳轉。首先將HelloWorldAppDelegate改名為MultiViewAppDelegate,并進行如下修改(代碼中粗體字部分)。

[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實例變量
  CGRect frame = [[UIScreen mainScreen] bounds];
  self.window = [[UIWindow alloc] initWithFrame:frame];
  // 創建母體Controller實例
  rootController = [[UITabBarController alloc] init];
  // 創建畫面1與畫面2的Controller實例
  ViewController1 *tab1 = [[[ViewController1 alloc] init] autorelease];
  ViewController2 *tab2 = [[[ViewController2 alloc] init] autorelease];
  // 將畫面1、畫面2的Controller實例以數組的形式追加到母體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

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

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

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

兩個畫面中的init方法的代碼如下。

[ViewController1.m]
-(id)init {
  if((self = [super init])){
    // 設置tabBar的相關屬性
    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])){
    // 設置tabBar的相關屬性
    self.title = @"您好";
    UIImage*icon = [UIImage imageNamed:@"ball2.png"];
    self.tabBarItem =
       [[[UITabBarItem alloc] initWithTitle:@"您好" image:icon tag:0] autorelease];
  }
  return self;
}

重寫的init方法中也沒有追加多少內容。設置title屬性后,導入圖標用的圖片,并將其設置到UIViewController的 tabBarItem屬性中。調用initWithTitle:image:tag:方法進行UITabBarItem類的初始化。第一個參數為標簽條中顯示的標題;第二個參數為指定顯示的圖標圖片;第三個參數為標簽的序號,此序號通常用于程序內檢索。

執行這個經過改造的工程后,將顯示如圖3-3所示的結果。

圖3-3 標簽實現的畫面跳轉

3.2.2 使用UINavigationController實現多層畫面跳轉

iPhone4手機的自帶應用程序中,既有使用UITabBarController來進行畫面切換控制的,也有使用UINavigationController來實現多畫面間的跳轉的。例如iPod音樂播放界面就采用了UITabBarController來進行畫面切換控制,而iPhone手機設置程序則采用了UINavigationController來實現多層次畫面間的跳轉,圖3-4、圖3-5是這兩個程序部分畫面的跳轉示意圖。

圖3-4 iPod音樂播放程序畫面跳轉示意圖

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

圖3-5 iPhone設置程序部分畫面跳轉示意圖

下面我們將上一節采用UITabBarController實現的畫面切換程序,再一次改造成采用UINavigationController來實現畫面的跳轉程序。其中兩個下一層的畫面保持不變,在這之前我們還將追加一個主畫面,主畫面非常簡單,只有一個iPhone表格視圖組成,兩個下層畫面的名稱依次顯示在表格中,當單擊任何一個名稱時將會跳轉到對應的下層畫面中,整個應用程序的跳轉示意圖如圖3-6所示。

圖3-6 改造目標程序的跳轉示意圖

要實現上述程序,首先要進行如下兩處修改。

● 在HelloWorldAppDelegate.m中將基準ViewController由UITableViewController替換為UINavigationController。

● 新追加主畫面的TopMenuController類。

需要注意一點,這里我們對畫面1以及畫面2的實現代碼其實是沒有進行任何修改的。只是留下了些原實例中追加的關于UITabBarController的注釋,請務必忽略。

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

[HelloWorldAppDelegate.m]
#import "HelloWorldAppDelegate.h"
#import "TopMenuController.h"
@implementation HelloWorldAppDelegate
@synthesize window = window_;
-(void)applicationDidFinishLaunching:(UIApplication *)application {
  // 初始化Window實例變量
  CGRect bounds = [[UIScreen mainScreen] bounds];
  window_ = [[UIWindow alloc] initWithFrame:bounds];
  // 創建基準的Controller對象
  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

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

下面是新追加的主菜單畫面TopMenuController的代碼。這里將TopMenuController以UITableViewController子類形式來創建。

[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>
    // 創建顯示用數組
    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 {
  // 檢查單元是否已經創建
  UITableViewCell* cell = [tableView dequeueReusableCellWithIdenti
fier:@"simple-cell"];
  if(!cell){
    // 沒有創建的單元新創建
    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:@"simple-cell"] autorelease];
  }
  // 設置單元中顯示的文本字符串
  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

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

圖3-7 UINavigationController的標題

其次,我們再確認一下tableView:didSelectRowAtIndexPath:方法的處理內容。此方法將在表單元被觸摸(單擊)時調用,參數indexPath中保存了具體被觸摸(單擊)的行信息。

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

這樣就算完成了整個層次的畫面跳轉應用程序。跳轉到下一層畫面后,將自動顯示如圖3-8所示的返回按鈕。

圖3-8 UINavigationController的返回按鈕

3.2.3 跳轉到任意畫面

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

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

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

圖3-9 替換歷史路徑

實現圖3-9所示的替換歷史路徑的代碼如下。

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

popToViewController:animated:方法的第一個參數中必須傳入UIViewController的實例,不是新創建的實例,而是實際跳轉過程中原畫面的實例。此時,可以通過UINavigationController的viewControllers屬性來參照。viewControllers屬性中保存的正是NSArray形式的跳轉畫面實例集合。

調用setViewControllers:animated方法進行跳轉畫面堆棧替換時,也可以viewControllers屬性中保存的實例集合為基礎,進行部分UIViewController實例的替換。

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

PC桌面軟件中經常可以看到如“文件讀取對話框”等模態對話框的畫面類型。這些畫面就顯示在主畫面的上方,當對話框中的操作結束,關閉對話框畫面后將顯示原來的畫面,屬于一種臨時畫面。iPhone應用程序中也能實現這種模態畫面,例如iPhone通信錄管理程序中,追加新的通信錄時也使用了這種模態畫面。

模態畫面沒有什么特別的地方,與其他畫面一樣也是由UIViewController的子類實現的畫面,只是調用的方式不同而已。以下是模態畫面顯示的調用方式以及顯示后關閉畫面的實例代碼。

// ModalDialog為UIViewController的子類
id dialog = [[[ModalDialog alloc] init] autorelease];
[self presentModalViewController:dialog animated:YES];
// 關閉模態UIViewController
[self dismissModalViewControllerAnimationed:YES];

如上述代碼所示,將UIViewController子類的實例作為presentModalViewController:animated:方法的第一個參數進行調用后,就能實現以模態方式顯示畫面。關閉時調用dismissModalViewControllerAnimationed:方法。模態畫面調用后的示意圖如圖3-10所示。

圖3-10 模態畫面顯示示意圖

從iPhone OS 3.0開始,追加了設置模態畫面顯示/隱藏時動畫效果的modalTranstionStyle屬性,可設置三種不同的值,分別如下。

● UIModalTransitionStyleCoverVertical:畫面從下向上徐徐彈出,關閉時向下隱藏(默認方式)。

● UIModalTransitionStyleFlipHorizontal:從前一個畫面的后方,以水平旋轉的方式顯示后一畫面。

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

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

// 以模態形式顯示的畫面
// 內容與普通畫面一樣
@interface ModalDialog :UIViewController
@end
@implementation ModalDialog
-(void)viewDidLoad {
  [super viewDidLoad];
  // 追加1個標簽
  UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
  label.backgroundColor = [UIColor blackColor];
  label.textColor = [UIColor whiteColor];
  label.textAlignment = UITextAlignmentCenter;
  label.text = @"您好。我是模態畫面。";
  [self.view addSubview:label];
  // 追加關閉按鈕
  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 {
  // 關閉模態對話框
  [self dismissModalViewControllerAnimated:YES];
}
@end
主站蜘蛛池模板: 东港市| 盐山县| 广南县| 密山市| 兰州市| 开远市| 南溪县| 海兴县| 榆林市| 翼城县| 高碑店市| 普洱| 古田县| 中方县| 红河县| 乳源| 周至县| 攀枝花市| 宝鸡市| 左云县| 南京市| 杭锦旗| 裕民县| 桑日县| 昭通市| 哈尔滨市| 始兴县| 敦化市| 天台县| 浑源县| 佳木斯市| 如皋市| 武冈市| 汨罗市| 进贤县| 共和县| 大丰市| 焦作市| 紫阳县| 龙南县| 滨州市|