iOS开发系列--XIB开发

来源:互联网 发布:鲁大师mac版下载 编辑:程序博客网 时间:2024/04/26 21:54

在iPhone开发中,一般都会用NIB文件来来负责界面显示,也就是MVC模型里面的视图对象,而NIB文件只包含用户界面元素,不包含任何源码,那么怎么让视图对象和视图控制器关联起来呢?这就需要用到两个非常重要的概念:插座变量(outlet)和文件拥有者代理对象(File's Owner)。

视图控制器的视图和Nib文件

视图控制器主要的职责就是配置和管理应用程序中所有的视图,一般来说,视图控制器的视图是放在一个Nib文件中,当然也可以不需要Nib文件,通过程序创建视图,典型的如UITableViewController这样的视图控制器,就可以不需要Nib文件。在创建视图控制器实例时,其中一个主要的构造函数 initWithNibName:bundle: 的第一个参数就是视图控制器对应的Nib文件的名字。视图控制器在其 loadView 方法中加载它的Nib文件。如果是使用 initWithNibName:bundle: 构造函数生成的实例,并且你想在视图加载完成后进行额外的设置,只要重写视图控制器的 viewDidLoad 方法就好了。

在Xcode中点击打开视图控制器的Nib文件(即RootViewController.xib文件),在Xcode中即可直接查看和编辑。文件包含三个对象,文件拥有者代理(File's Owner),第一响应者代理(First Responder)以及一个视图(View)。视图(View)是视图控制器的主视图,在主视图中还可以添加若干子视图。文件拥有者代理(File's Owner)代表Nib文件对应的视图控制器类。理解文件所有者代理的角色,以及如何建立文件所有者和Nib文件中界面元素之间的连接,是非常重要的。

201106072252.jpg

小贴士: 在Xcode中编辑Nib文件时,可以通过点击右上角工具栏按钮201106072256.jpg 显示隐藏相应面板,方便对界面编辑和属性设置。 

文件拥有者(File's Owner)

在一个Nib文件中,文件拥有者对象是其中最重要的对象之一,因为正是通过它,来建立起应用程序代码和Nib界面文件中对象之间的连接,具体来说,它就是对应Nib文件的视图控制器对象。以本项目为例,RootViewController.xib这个Nib文件的文件拥有者对象就是RootViewController类的实例。

一般来说,在使用模板同时创建UIViewController文件和对应的Nib文件时,它默认会设置Nib文件对应的文件拥有者为创建的UIViewController类。如果要修改或者设置Nib文件对应的文件拥有者,可以使用 Identity Inspector 面板进行设置。

201106080842.jpg

如上图所示, 本项目的RootViewController.xib文件对应的文件所有者,在Identity Inspector 面板中,Custom Class部分的Class项,可以看到对应的值是RootViewController,这表示文件拥有者就是RootViewController类的实例,就可以在Xcode中访问文件拥有者类里面标志为IBOutlet的属性和IBAction的方法,和Nib文件中的界面元素建立关联。

视图插座变量

在Xcode中,使用 Inspector 面板,或者在连接面板,可以查看、创建、删除对象之间的连接。要查看视图控制器的连接,可以通过以下步骤:

  1. 在Xcode的界面中,从左侧的文件组选中要查看的视图控制器的Xib文件
  2. 在视图编辑界面,点击选中 File's Owner
  3. 在 Inspector 面板,选中 Connection inspector,这里会显示文件所有者所有的插座连接
  4. 在视图编辑界面,按住Control键点击 File's Owner 或者在 File's Owner上点击右键,弹出一个黑色半透明的面板显示文件所有者的所有连接

201106090009.jpg

在上面第三步,右侧面板显示的连接面板和右键点击File's Owner弹出的半透明连接面板,显示的信息和作用都是一样的,可以根据个人习惯灵活使用。到目前为止唯一的连接是视图控制器的 view 插座变量。一个插座变量就对应视图控制器类的一个属性(有时候也可以是一个实例变量),只不过这个属性和nib文件中的某个界面元素连接在一起。此处的view的连接,表明当nib文件 RootViewController.xib 被加载,并且UIView的实例解档之后,视图控制器的view实例变量会被设置为指向nib文件中的视图。

201106090039.jpg

中间测试

在项目开发中,尤其在对开发工具和语言不熟悉的时候,需要经常性的对新增的功能进行测试,以确保当前功能运行是正常的。比如我们新增了RootViewController这个自定义视图控制器,需要去测试一下它是不是已经成功添加。要测试视图控制器工作正常,简单的办法修改视图控制器的视图的背景色,例如修改为粉红色背景,然后重新运行,看看是不是界面变成了红色背景。

要设置视图控制器的视图的背景色,步骤如下:

  1. 在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
  2. 在右侧的功能区域,选择属性面板(Attributes inspector)
  3. 在编辑区域,选择视图
  4. 在视图的属性面板,点击背景色(Background)对应的颜色下拉框,会弹出颜色选择面板
  5. 在颜色选择面板,选择一个合适的颜色,例如粉红色
  6. 保存nib文件
  7. 点击左上角工具栏的Run按钮,编译运行项目
201106090138.jpg

正常情况下,编译应该不会出现任何错误,运行后会弹出模拟器,结果如下图所示:

201106090251.jpg

确认没有问题后,再将应用的背景色还原。还原的话,将视图的背景色设置为白色就好了。

配置视图

Xcode提供了一套对象库,可以直接添加到Nib文件中。其中一部分示界面元素,例如按钮和文本输入框;其他一部分是控制器对象,例如视图控制器。我们当前项目的nib文件已经包含了视图,现在只要添加按钮和文本输入框就好了。从对象库中将用户界面元素拖动到视图中,基本步骤如下:

  1. 在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
  2. 在右侧的功能区域,显示对象库(object library)
  3. 添加一个按钮(UIButton),一个文本输入框(UITextField),两个文本标签(UILabel)到视图中。可以从对象库里面拖动并将它们放到视图
    201106090318.jpg
  4. 参考前面的原型设计,对界面元素的尺寸和布局进行调整
  5. 将右侧功能区域切换到属性面板(Attributes inspector)
  6. 选中文本输入框(Text Field),设置Placehold属性为“请输入姓名”
  7. 选中左上侧的文本标签(UILabel),设置Text属性为“姓名”
  8. 选中下面的文本标签(UILabel),设置Text属性为空,Alignment属性设置为居中对齐
  9. 选中按钮(UIButton),设置Title属性为“招呼”
  10. 设置好的界面如下所示:201106090505.jpg

如果我们想让用户在输入时有一些更好的体验,比如用户输入英文名时,默认会首字母大写;比如键盘会显示完成(Done)按键,点击后完成输入隐藏键盘。要支持这样的输入细节,通过设置文本框属性就可以完成:

  • 在Capitalization下拉列表,选择Words,以支持首字母大写
  • 在Return Key下拉列表,选择Done,以支持键盘上显示完成(Done)按键

201106090522.jpg

保存文件后,编译运行程序,可以看到运行的界面效果和我们在Xcode中摆放的效果是一样的。点击按钮,按钮会高亮,在文本输入框中点击,会弹出输入键盘,键盘里可以看到完成(Done)按钮。但是还不能根据输入的内容去显示文字,还不能隐藏键盘,因为目前我们还仅仅完成了视图部分的工作,还需要让视图中的对象和视图控制器的对象之间建立连接,并添加相应的逻辑,才能实现。

201106090526.jpg

实现视图控制器

实现视图控制器需要完成以下几件事:

  1. 定义插座变量和动作方法,和Nib文件的视图中的界面元素进行关联
  2. 实现点击按钮后的相关逻辑——根据输入的名字显示相应的招呼语,判断输入的名字是不是为空是不是超长
  3. 用户点击键盘上的完成(Done)按键后,键盘会消失

建立连接

从业务角度来看,我们需要和界面的几个元素建立关联:

  1. 文本输入框,获取它的输入文字
  2. 文本标签,让它显示特定文字
  3. 按钮,响应它的点击事件

在Xcode4之前,Interface Builder和Xcode是分开的,一般是先在Xcode中定义好插座变量和动作方法,然后再在InterfaceBuilder中去建立界面元素和视图控制器之间的连接,到Xcode4之后,Interface Builder和Xcode已经统一合并在了一起,所以这部分也有一些变化,Xcode4让这部分工作变的更加容易一些,可以直接从视图编辑界面拖动连接到代码文件。

在我们正在开发的SayHello项目中,现在我们需要添加一个动作方法到视图控制器,当界面上的按钮被点击时,它会发送一个sayHello:消息到视图控制器,所以接下来要为按钮创建一个sayHello:动作方法:

  1. 1、在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
  2. 2、显示Assistant editor201106090630.jpg
  3. 3、让Assistant显示视图控制器的头文件(RootViewController.h)
  4. 4、按住Control键,从Nib文件中的按钮拖动到头文件的方法声明代码区域201106090634.jpg
  5. 在弹出的面板中,将按钮和视图控制器之间的连接设置为动作(Action)
    • 设置 Connection 为 Action
    • 设置 Name 为 sayHello:
    • 设置 Type 为 id
    • 设置 Event 为 Touch Up Inside,也就是用户在点击按钮,然后释放后触发
    • 设置 Arguments 为 Sender
    • 201106090639.jpg
  6. 点击Connect建立连接

通过上面的为按钮添加动作的操作,完成了两件事

  1. 添加了相应的代码到视图控制器的类中
    头文件中增加了如下代码:

    - (IBAction)sayHello:(id)sender;

    并且实现文件中增加了相应的实现方法:

    - (IBAction)sayHello:(id)sender {

    }

    IBAction 是一个特殊的关键字,它唯一的作用是告诉Interface Builder将某个方法当成目标/动作关联中的动作。它被定义为void。

  2. 建立了按钮到视图控制器之间的连接。建立连接的意义,等同于在按钮上调用 addTarget:action:forControlEvents: ,并且 target 是文件拥有者(File's Owner)也就是视图控制器,action 是 sayHello: 方法,对应的事件是 UIControlEventTouchUpInside。

接下来要建立文本输入框和文本标签之间的连接:

  1. 1、在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
  2. 2、显示Assistant editor201106090630.jpg
  3. 3、让Assistant显示视图控制器的头文件(RootViewController.h)
  4. 4、按住Control键,从Nib文件中的文本输入框拖动到头文件的方法声明代码区域201106090654.jpg
  5. 5、在弹出的面板中,将文本输入框和视图控制器之间的连接设置为插座(Outlet)
    • 设置 Connection 为 Outlet
    • 设置 Name 为 nameTextField
    • 设置 Type 为 UITextField
    • 201106090704.jpg
  6. 6、点击Connect建立连接

通过上面的为文本输入框添加插座变量的操作,完成了两件事

  1. 添加了相应的代码到视图控制器的类中
    头文件中增加了如下代码:

     

    @property (nonatomic, retain) IBOutlet UITextField *nameTextField;

    并且实现文件中增加了相应的实现方法:

    在顶部增加了:

     

    @synthesize nameTextField;

    在 dealloc 方法中添加了

     

     

    [nameTextField release];

    在 viewDidUnload 方法中添加了:

     

     

    [self setNameTextField:nil];

    IBOutlet是一个特殊的关键字,它唯一的作用是通知Interface Builder将某个实例变量或者属性当成插座变量。实际上,这个关键字被定义为空白,因此在编译的时候它没有任何作用。

  2. 建立了文本输入框到视图控制器之间的连接。建立连接的意义,等同于在视图控制器上调用 setNameTextFiled: 方法,将文本输入框作为参数传入。

按照上面创建文本输入框插座变量相同的方法,再建立用来显示问候语的文本标签的插座变量,并且将插座变量命名为 greetingLabel,类型为 UILabel。

实现逻辑代码

点击视图中的按钮,它会向视图控制器发送 sayHello: 消息,之后,视图控制器会取得文本输入框文字内容,根据内容来更新用来显示问候语的文本标签的内容。以下是RootViewController.m文件中 sayHello: 方法代码的实现:

- (IBAction)sayHello:(id)sender {

// 获取文本输入框内容,并存储到变量中

NSString *nameString = nameTextField.text;

 

// 检查输入的名字是否为空,如果为空,弹出提示信息

if (nameString.length == 0) {

UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"名字不能为空" message:@"请输入名字后,重新点击按钮。" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

[alertView show];

[alertView release];

greetingLabel.text = @"";

return;

}

 

// 检查名字是不是超过16个字符,超过16个字符自动截断

if (nameString.length > 16) {

nameString = [nameString substringToIndex:16];

}

 

// 根据输入的名字,生成问候语

NSString *greeting = [NSString stringWithFormat:@"你好,%@!", nameString];

// 显示问候语

greetingLabel.text = greeting;

}

对于这个方法有几点补充说明:

  • UIAlertView是专门用来显示消息提示对话框
  • stringWithFormat:方法符串按照格式化字符串所指定的格式创建一个新字符串。%@表明此处应该使用一个字符串对象来代替。



同时添加多个outlet
在IB中,选中一个view并右键点击,将会出现灰色的HUD,可以在其上方便地拖拉或设定事件和outlet。你可以同时打开多个这样的面板来一次性添加所有outlet。右键点击面板,随便拖动一下面板,然后再打开另一个。你会发现前一个面板也留下来了,这样你就可以方便地进行拖拽设定了。
 

多个Outlet HUD
当然,对于成组和行为类似的IBOutlet,应该直接使用IBOutletCollection来进行处理会更方便。



问题1:下图中,如果弹出框中红色矩形没有内容,要如何建立?如何让xib控件与ViewController中的变量关联起来?



以上资料经综合整理各方面资料而成。
0 0
原创粉丝点击