iOS 8案例开发大全
上QQ阅读APP看书,第一时间看更新

实例011 使用Interface Builder的故事板

实例说明

通过使用Interface Builder(IB),确实能帮助开发人员快速地创建一个应用程序界面,但是它不仅是一个GUI绘画工具,还可以帮助开发人员在不编写任何代码的情况下添加应用程序功能。IB向Objective-C开发者提供了包含一系列用户界面对象的工具箱,这些对象包括文本框、数据表格、滚动条、弹出式菜单等控件。IB的工具箱是可扩展的,也就是说,所有开发者都可以开发新的对象,并将其加入IB的工具箱中。开发者只需要从工具箱中简单地向窗口或菜单中拖曳控件即可完成界面的设计。然后,用连线将控件可以提供的“动作”(Action)、控件对象分别和应用程序代码中对象“方法”(Method)、对象“接口”(Outlet)连接起来,就完成了整个创建工作。与其他图形用户界面设计器,例如Microsoft Visual Studio相比,这样的过程减小了MVC模式中控制器和视图两层的耦合,提高了代码质量。

当把Interface Builder集成到Xcode中后,和原来的版本相比主要有如下几点不同。

(1)在导航区选择xib文件后,在编辑区会显示xib文件的详细信息,这说明Interface Builder和Xcode确实是整合在一起了,如图2-1所示,选择xib文件时双击会弹出新窗口,这和以前的步骤基本一样。

图2-1 显示xib文件

(2)在工具栏选择View控制按钮,点击图2-2所示中最右边的按钮可以调出工具区,如图2-3所示。

图2-2 View控制按钮

图2-3 工具区

在图2-3的工具区中,最上面的按钮分别是4个Inspector:Identity、Attributes、Size、Connections。工具区下面就是可以往View上拖的控件。

(3)隐藏导航区。

若专心设计UI,导航区就显得多余了,除非屏幕特别大。在刚才提到的“View控制按钮”中点击第一个,将导航区隐藏,如图2-4所示。

图2-4 隐藏导航区

(4)关联方法和变量。

这是一个所见即所得功能,刚才已经打开隐藏很多区了,现在要涉及一个新View:Assistant View,它是编辑区的一部分。此时只需将按钮(或者其他控件)拖到代码指定地方即可。在“拖”时需要按住“Ctrl”键。怎么让Assistant View显示要对应的“.h”文件呢?使用这个View上面的选择栏进行选择。通过使用Xcode和Cocoa工具集,可手工编写生成iOS界面的代码:实例化界面对象,指定它们出现在屏幕的什么位置,设置对象的属性以及使其可见。例如通过下面的代码,可以在iOS设备屏幕设备的一角中显示文本“Hello Xcode”。

- (BOOL)application:(UIApplication *)application
      didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc]
                    initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    UILabel *myMessage;
    UILabel *myUnusedMessage;
    myMessage=[[UILabel alloc]
              initWithFrame:CGRectMake(30.0,50.0,300.0,50.0)];
    myMessage.font=[UIFont systemFontOfSize:48];
    myMessage.text=@"Hello Xcode";
    myMessage.textColor = [UIColor colorWithPatternImage:
                            [UIImage imageNamed:@"Background.png"]];
    [self.window addSubview:myMessage];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

如果要创建一个包含文本、按钮、图像以及数十个其他控件的界面,会耗费很多的事件。甚至如果做一些细微的修改,将需要阅读所有的代码。在过去的一段时间内,诞生了采用多种方法的图形界面生成器,其中最常见的实现方法之一是让开发人员“绘制”界面,并在幕后创建生成该界面的代码。在这种情况下,要做任何调整都必须手工编辑代码,这令人难以接受。

另一种常见的策略是维护界面定义,但将实现功能的代码直接关联到界面元素。不幸的是,这意味着如果要修改界面或将功能从一个U1元素切换到另一个,则必须移动代码。

而Interface Builder的工作原理与此不同,它不是自动生成界面代码,也不是将源代码直接关联到界面元素,而是生成实时的对象,并通过称为连接(Connection)的简单关联将其连接到应用程序代码。当开发人员需要修改应用程序功能的触发方式时,只需修改连接即可。要改变应用程序使用创建的对象的方式,只需连接或重新连接即可。

本实例是通过Interface Builder的故事板实现的,Storyboarding(故事板)是从iOS 5开始新加入的Interface Builder(IB)的功能。主要的功能是在一个窗口中显示整个app用到的所有或者部分的页面,并且可以定义各页面之间的跳转关系,大大增加了IB的便利性。

具体实现

首先打开项目“lianjie”,并双击文件“ianjie.xcworkspace”,这将在Xcode中打开该项目,如图2-5所示。

图2-5 在Xcode中打开项目

加载该项目后,展开项目代码编组(Disconnected),并单击文件MainStoryboard.storyboard,这个故事板文件包含该应用程序将把它显示为界面的场景和视图。Xcode将刷新,并在Interface Builder编辑器中显示场景,如图2-6所示。

图2-6 显示应用程序的场景和相应的视图

由图2-6所示的效果可知,该界面包含了如下4个交互式元素。

· 一个按钮栏(分段控件)。

· 一个按钮。

· 一个输出标签。

· 一个Web视图(一个集成的Web浏览器组件)。

这些控件将与应用程序代码交互,让用户选择花朵颜色并单击“给我花朵”按钮时,文本标签将显示选择的颜色,并从网站http://www.floraphotographs.com随机取回一朵这种颜色的花朵。预期的执行结果如图2-7所示。

图2-7 执行效果

但是到目前为止,这个演示程序没有任何功能,这是因为现在还没有将界面连接到应用程序代码,因此它不过是一张漂亮的图片。为让应用程序能够正常运行,将创建到应用程序代码中定义的输出口和操作的连接。

(1)输出口和操作。

输出口(Outlet)是一个通过它可引用对象的变量,假如Interface Builder中创建了一个用于收集用户姓名的文本框,在代码中为它创建一个名为userName的输出口。这样便可以使用该输出口和相应的属性获取或修改该文本框的内容。

另一方面,操作(Action)是代码中的一个方法,在相应的事件发生时调用它。有些对象(如按钮和开关)可在用户与之交互(如触摸屏幕)时通过事件触发操作。通过在代码中定义操作,Interface Builder可使其能够被屏幕对象触发。

将Interface Builder中的界面元素与输出口或操作相连,这样就可以创建一个连接。为了让应用程序Disconnected能够成功运行,需要创建到如下所示的输出口和操作的连接。

· ColorChoice:一个对应于按钮栏的输出口,用于访问用户选择的颜色。

· GetFlower:这是一个操作,它从网上获取一幅花朵图像并显示它,然后将标签更新为选择的颜色。

· ChosedColor:对应于标签的输出口,将被getFlower更新以显示选定颜色的名称。

· FlowerView:对应于Web视图的输出口,将被getFlower更新以显示获取的花朵图像。

(2)创建到输出口的连接。

要想建立从界面元素到输出口的连接,可以先按住“Control”键,并同时从场景的View Controller图标(它出现在文档大纲区域和视图下方的图标栏中)拖曳到视图中对象的可视化表示或文档大纲区域中的相应图标。读者可以尝试对按钮栏(分段控件)进行这样的操作。按住“Control”键的同时,再单击文档大纲区域中的View Controller图标,并将其拖曳到屏幕上的按钮栏。拖曳时将出现一条线,这样能够轻松地指向要连接的对象。当松开鼠标时,将出现一个下拉列表,其中列出可供选择的输出口,如图2-8所示,再次选择colorChoice。

图2-8 出现一个下拉列表

Interface Builder知道什么类型的对象可连接到给定的输出口,因此它只显示适合当前要创建的连接的输出口。对文本为Your Color的标签和Web视图重复上述过程,将它们分别连接到输出口chosenColor和flowerView。

在这个演示工程中,其核心功能是通过文件ViewController.m实现的,其主要代码如下所示。

#import "ViewController.h"
@implementation ViewController
@synthesize colorChoice;
@synthesize chosenColor;
@synthesize flowerView;
-(IBAction)getFlower:(id)sender {
      NSString *outputHTML;
      NSString *color;
      NSString *colorVal;
      int colorNum;
      colorNum=colorChoice.selectedSegmentIndex;
      switch (colorNum) {
          case 0:
                color=@"Red";
                colorVal=@"red";
                break;
          case 1:
                color=@"Blue";
                colorVal=@"blue";
                break;
          case 2:
                color=@"Yellow";
                colorVal=@"yellow";
                break;
          case 3:
                color=@"Green";
                colorVal=@"green";
                break;
      }
      chosenColor.text=[[NSString alloc] initWithFormat:@"%@", color];
      outputHTML=[[NSString alloc] initWithFormat:@"<body style='margin: 0px; padding:
0px'><img  height='1200'  src='http://www.floraphotographs.com/showrandom.php? color=%@
'></body>", colorVal];
      [flowerView loadHTMLString:outputHTML baseURL:nil];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
    [self setFlowerView:nil];
    [self setChosenColor:nil];
    [self setColorChoice:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface
Orientation
{
    // Return YES for supported orientations
    return (interfaceOrientation ! = UIInterfaceOrientationPortraitUpsideDown);
}
@end

(3)创建到操作的连接。

连接到操作的方式稍有不同。对象的事件触发代码中的操作(方法),因此连接的方向正好相反:从触发事件的对象连接到场景的View Controller。虽然可以像连接输出口那样按住“Control”键并拖曳来创建连接,但是再次建议不要这样做,因为用户无法指定哪个事件将触发它,究竟轻按按钮触发还是用户的手指离开按钮触发呢?

其实这个操作可以被很多不同的事件触发,因此需要确保选择了正确的事件,而不是让Interface Builder去决定。所以选择将调用操作的对象,并单击Utility区域顶部的箭头图标以打开Connections Inspector(连接检查器)。也可以选择菜单View→Utilities→Show Connections Inspector(Option+ Command+6)。

Connections Inspector显示了当前对象(这里是按钮)支持的事件列表,如图2-9所示。

图2-9 使用Connections Inspector操作连接

每个事件旁边都有一个空心圆圈,要将事件连接到代码中的操作,可单击相应的圆圈并将其拖曳到文档大纲区域中的View Controller图标。假如要将按钮Get Flower连接到方法getFlower,可选择该按钮并打开Connections Inspector(Option+Command+6)。然后将Touch Up Inside事件旁边的圆圈拖曳到场景的View Controller图标,再松开鼠标。当系统询问时选择操作getFlower,如图2-10所示。

图2-10 选择希望界面元素触发的操作

在建立连接后检查器会自动更新,以显示事件及其调用的操作,如图2-11所示。如果单击了其他对象,Connections Inspector将显示该对象到输出口和操作的连接。

图2-11 更新后的界面效果

到现在为止,已经将界面连接到了支持它的代码。单击Xcode工具栏中的Run按钮,在iOS模拟器或iOS设备中便可以生成并运行该应用程序。执行效果如图2-12所示。

图2-12 执行效果

其实开发人员无需编写代码便可建立连接。虽然在Interface Builder中建立的大部分连接都位于对象和在代码中定义的输出口或操作之间,但有些对象实现了一些内置操作,不需要编写任何代码。例如,Web视图实现了包括goForward和goBack在内的操作。通过使用这些操作,可以给该视图添加基本的导航功能。为此,只需将按钮的Touch Up Inside事件拖曳到Web视图对象(而不是View Controller图标)。正如前面指出的,系统将要求开发人员指定要连接到哪个操作,但这次连接的操作并非开发人员自己编写的。

(4)使用快速检查器编辑连接。

在连接到界面时,常犯的一种错误是创建的连接并非我们需要的。经过一些拖曳操作后,界面突然间不正确,不能正常运行了。要检查已建立的连接,可选择一个对象,并打开前面讨论过的Connections Inspector,也可右击Interface Builder编辑器或文档大纲区域中的任何对象,以打开快速检查器(Quick Inspector)。这将出现一个浮动窗口,其中列出了与该对象相关联的所有输出口和操作,如图2-13所示。

图2-13 右键单击对象以快速检查其连接

(5)对象身份。

当将对象拖放到界面中时,实际上是在创建现有类(按钮、标签等)的实例。在这种情况下,需要给Interface Builder提供帮助,指出它应使用的子类。例如,假设创建了标准按钮类UIButton的一个子类,并将其命名为ourFancyButtonClass。然后将一个按钮拖放到场景中以表示自定义按钮,但加载故事板文件时,创建的却是UIButton对象。

为了修复这种问题,可选择加入到视图中的按钮,单击Utility区域顶部的窗口图标或选择菜单View→Utilities→Show Identity Inspector(Option+ Command+3)打开Identity Inspector,再通过下拉列表/文本框指定在运行阶段加载界面时要实例化的类,如图2-14所示。

图2-14 在InterfaceBuilder中设置对象的身份