3.1 UIViewController与画面的关系

3.1.1 UIViewController概要

UIViewController在UIKit中主要功能是用于控制画面的切换,其中的view属性(UIView类型)管理整个画面的外观。

在开发iPhone应用程序时UIViewController是否必不可少呢?显然不是这样,在第1章中的Hello World程序中显然就没有使用UIViewController,这说明不使用UIViewController也能编写出iPhone应用程序。第1章的Hello World程序只有一个画面,我们再考虑拥有两个画面的应用程序的情况。例如第一个画面与Hello World程序的画面类似,画面中显示“Hello World!”,当触摸画面下方的按钮后切换到另外一显示“您好!”的画面。其实我们仍然可以通过改变画面中的控件属性来实现画面外观的切换,例如此时可采取将不需要的控件都隐藏起来的方法。此时仍然不需要UIViewController。

但是,像上述这样实现画面外观的切换,同一个画面中实际上包含别的画面的控件,代码看起来将非常凌乱。如果能将不同外观的画面进行整体的切换显然更合理,UIViewController正是用于实现这种画面切换方式的,其切换示意图如图3-1所示。

图3-1 UIViewController画面管理示意图

图3-1中分别由两个UIViewController管理两个画面,画面内容分别为“Hello,World!”及“您好,世界!”,当触摸“画面跳转”按钮后跳转到另一画面中。这是一个最简单的画面跳转实例,事先必须将两个画面内容(UIView及其子元素)追加到UIWindow对象中,但显示时只显示其中一个画面。具体实例代码下一小节中有详细介绍。

3.1.2 UIViewController的切换

本节我们实际使用UIViewController来创建画面。以第1章“Hello World!”实例为基础,我们再创建一个新的画面上面显示中文“您好、世界!”,并在这两个画面间实现自由切换。

不过大家需要注意的是,这里实现的画面跳转(或称切换)方法并非最佳的跳转方法,目的不过是让读者了解UIViewController管理画面的方式,理解以UIViewController为单位切换画面的样子,如图3-1所示。

本实例中有两个画面,第一个画面中显示“Hello,World!”,背景为白色,下方布置有一个“画面跳转”按钮。第二个画面中显示“您好、世界!”,背景为黑色,下方也布置有一个“画面跳转”按钮。当触摸“画面跳转”按钮时,可在两个画面间进行显示切换。两个画面的代码如下。

[ViewController1.h]
#import <UIKit/UIKit.h>
@interface ViewController1 :UIViewController
@end
[ViewController1.m]
#import "ViewController1.h"
@implementation ViewController1
-(void)viewDidLoad {
  [super viewDidLoad];
  // 追加“Hello,world!”标签
  // 背景为白色、文字为黑色
   UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
  label.text = @"Hello,world!";
  label.textAlignment = UITextAlignmentCenter;
  label.backgroundColor = [UIColor whiteColor];
  label.textColor = [UIColor blackColor];
  label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIVie wAutoresizingFlexibleHeight;
  [self.view addSubview:label];
  // 追加按钮
  // 单击按钮后跳转到其他画面
  UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [button setTitle:@"画面跳转" forState:UIControlStateNormal];
  [button sizeToFit];
  CGPoint newPoint = self.view.center;
  newPoint.y += 50;
  button.center = newPoint;
  button.autoresizingMask =
    UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexib leBottomMargin;
  [button addTarget:self
             action:@selector(buttonDidPush)
   forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:button];
}
-(void)buttonDidPush {
  // 自己移向背面
  // 结果是ViewController2显示在前
  [self.view.window sendSubviewToBack:self.view];
}
@end
[ViewController2.h]
#import <UIKit/UIKit.h>
@interface ViewController2 :UIViewController
@end
[ViewController2.m]
#import "ViewController2.h"
@implementation ViewController2
-(void)viewDidLoad {
  [super viewDidLoad];
  // 追加“您好、世界!”标签
  // 背景为黑色、文字为白色
  UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
  label.text = @"您好、世界!";
  label.textAlignment = UITextAlignmentCenter;
  label.backgroundColor = [UIColor blackColor];
  label.textColor = [UIColor whiteColor];
  label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIVie wAutoresizingFlexibleHeight;
  [self.view addSubview:label];
  // 追加按钮
  // 单击按钮后画面跳转
  UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [button setTitle:@"画面跳转" forState:UIControlStateNormal];
  [button sizeToFit];
  CGPoint newPoint = self.view.center;
  newPoint.y += 50;
  button.center = newPoint;button.autoresizingMask =
    UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexib leBottomMargin;
  [button addTarget:self
             action:@selector(buttonDidPush)
  forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:button];
}
-(void)buttonDidPush {
  // 自己移向背面
  // 结果是ViewController1显示在前
  [self.view.window sendSubviewToBack:self.view];
}
@end

ViewController1与ViewController2都是继承UIViewController的子类。为了追加画面控件(UIView及其子类)需要重写(Overwrite)viewDidLoad方法,其中分别创建标签与按钮,并通过addSubview:方法追加到画面(self.view)中。viewDidLoad方法在UIViewController拥有的UIView(画面基础UIView)被导入后调用。此UIView可通过UIViewController的view属性参照,控件追加到画面中的代码如下所示。

[self.view addSubview:控件实例];

另一个重要的知识是,触摸按钮后实现画面切换。首先调用addTarget:action:forControlEvents:方法设置按钮被触摸时的响应方法buttonDidPush,关于按钮等控件的响应事件的设置第4.2节(UIButton)将进行介绍。buttonDidPush方法中只有如下一行代码,实现画面的切换。

[self.view.window sendSubviewToBack:self.view];

作为UIWindow的子元素,UIView可以通过其Window属性参照UIWindow(通常应用程序只有唯一的UIWindow)。这行代码的作用是“将画面自己隐藏到背面去”,因为原来UIWindow中包含有两个画面,当前画面隐藏到背面后,另一个画面就会显示在前面。

至于将两个画面(UIView)追加到UIWindow中的处理在HelloWorldAppDelegate类中实现,以下是HelloWorldAppDelegate的详细代码,黑体字部分表示向UIWindow中追加两个画面。

[HelloWorldAppDelegate.h]
#import <UIKit/UIKit.h>
@interface HelloWorldAppDelegate :NSObject <UIApplicationDelegate> {
  UIWindow*window_;
  UIViewController*viewController1_;
  UIViewController*viewController2_;
}
@property(nonatomic,retain)UIWindow*window;
@end
[HelloWorldAppDelegate.m]
#import "HelloWorldAppDelegate.h"
#import "ViewController1.h"
#import "ViewController2.h"
@implementation HelloWorldAppDelegate
@synthesize window = window_;
-(void)applicationDidFinishLaunching:(UIApplication *)application {
  // 初始化Window
  CGRect bounds = [[UIScreen mainScreen] bounds];
  window_ = [[UIWindow alloc] initWithFrame:bounds];
  // 创建ViewController1与ViewController2
  // 并将其画面(view)追加到Window中
  viewController1_ = [[ViewController1 alloc] init];
  viewController2_ = [[ViewController2 alloc] init];
  [window_ addSubview:viewController1_.view];
  [window_ addSubview:viewController2_.view];
  // ViewController1放在前面显示
  [window_ bringSubviewToFront:viewController1_.view];
  [window_ makeKeyAndVisible];
}
-(void)dealloc {
  [viewController1_ release];
  [viewController2_ release];
  [window_ release];
  [super dealloc];
}
@end

在应用程序初始化applicationDidFinishLaunching:方法中,首先创建两个画面的实例,然后分别追加(使用addSubview:方法)到UIWindow中,最后调用UIWindow的bringSubviewToFront:方法将第一个画面显示在前面。

实例运行后的效果如图3-2所示。

图3-2 画面切换实例