1.4 修改模板
iOS应用开发
好了,言归正传。让我们开始创建一些新的东西。我们将为主视图添加一个标签,用来显示一个简短的文本。再为背面视图添加一个文本框,在文本框中用户可以修改主视图中的文本。那么,让我们开始吧!
1.4.1 修改主视图
再次打开MainStoryboard.storyboard文件,并且放大主视图控制器场景。就我来说,背景有一点灰暗,对它做一点修改。选择视图对象,然后切换到Attributes inspector。将Background属性改为Light Gray Color(见图1.17)。接着,选择info按钮并且将它的Type设置改为Info Dark(见图1.18)。
现在我们需要添加一个标签。Xcode使得添加用户界面对象变得非常容易。只要从Library面板(实用工具区的下半部分)中拖动想要的对象放置到场景上就行。确保Object library是显示的(控件库选择工具条右边起第二个立方体图标)(见图1.19),并且滚动它使得标签对象可见。点击标签对象并且将它从Library面板中拖动到主视图控制器场景的视图中。
Xcode会帮助你准确地放置控件。当你将标签拖过编辑区域时,它高亮并标出当前的视图。它还添加了蓝色的引导线,助于我们准确地放置对象。拖动标签,直到它垂直居中并且与视图的左侧边缘对齐,如图1.20所示。
当你松开标签时,在它的周围会显示8个蓝色的小圆点。你可以点击并且拖动这些锚点来改变标签的大小。点击标签右侧并且拉伸它,直到碰到右侧边缘的引导线。接着,使它变为视图的一半高。现在,仍然选中标签,让我们改变它的外观。
打开Attributes inspector,在Alignment属性中,点击文本居中的按钮。接着点击Font属性文本域最右侧的图标。这将会打开一个弹出窗口。将字体设置成System Bold,Size设置成24(见图1.21)。现在让我们来改变文本的内容吧!你可以修改标签的Text属性,或者也可以双击标签然后直接修改。使用Hello World来替代默认的内容“Label”。
最后,点击并且拖动标签直到它水平和垂直都居中(如果你不能移动标签,尝试一下点击View来取消选中,然后再次选中和拖动标签)。如果你正确完成了以上的所有操作,左侧和右侧边缘的引导线也会显示(见图1.22)。
运行应用。我们的修改将会在主视图中显示出来。
1.4.2 添加输出口
如果我们想要在运行时改变标签的文本内容,我们需要在代码中有一个访问它的方法。最简单的方法是在视图控制器中添加一个输出口。在Xcode 4.0推出之前,如果手动修改代码,则需要在Xcode和Interface Builder之间来回切换。然而现在有更简便的方式了。
首先,我们可能想要收起场景列表,点击编辑区左下角的圆形灰色的按钮。接着,点击Assistant Editor按钮(见图1.23)。
按住Control键点击标签,然后将其拖动到头文件中去。你会看到一条蓝色的线从标签连接到光标。将光标放在@end指令之上的区域,如图1.25所示,然后松开鼠标。
注意:
虽然Xcode在自动选择正确的配套文件方面的功能很强大,但是有时候也可能会出错,或者你想要选择另外一个文件。你可以在跳转工具条中完成这个操作。选中叶项目,你就能以大致相同的挑选规则选择一个替代文件。选中根项目,你就可以选择不同的挑选规则。Xcode提供了一些不同的视具体环境而定的挑选规则。如果必要的话,你也可以手动选择配套文件。
Xcode将会对HWMainViewController.h文件、HWMainView Controller.m文件和MainStoryboard.storyboard文件做一些改变。在头文件中,它声明了我们的标签的属性。
import "HWFlipsideViewController.h"
@interface HWMainViewController : UIViewController
<HWFlipsideViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UILabel *label;
@end
在实现文件中,Xcode生成我们的标签属性,并且在视图卸载的时候把它设置为nil。这有助于释放不再需要的内存。
#import "HWMainViewController.h"
@implementation HWMainViewController
@synthesize label;
....
- (void)viewDidUnload
{
[self setLabel:nil];
[super viewDidUnload];
// 释放主视图保留的任何子视图
// 例如 self.myOutlet = nil;.
}
在storyboard文件中,Xcode连接了标签和新创建的输出口。你可以通过Connection inspector来查看这些连接。此外,按住Control键点击主视图控制器图标,也可以打开连接对话框(见图1.27)。
1.4.3 添加文本字段
这一节前面几步操作基本上是重复我们上节在主视图里的,只是这里使用的是文本字段控件,而不是标签。请确保打开了MainStoryboard.
``storyboard,并且放大背面视图控制器。现在,从Library面板中拖动一个文本字段控件。调整大小使它充满整个视图。
这次我们不需要改变文本字段的高度或者属性。只要为文本字段创建一个输出口,按住Control键点击文本字段拖动到委托上面就可以了。将输出口命名为labelText。最后,将它放置到背面视图的上半部分,否则,它会被键盘覆盖。
无论何时想要改变标签的文本,我们只需要从labelText输出口中获得文本值并且复制到我们的标签输出口就行。最简单的解决办法就是只在用户关闭背面视图的时候改变标签。打开HWMainViewController.m文件并且找到flipsideViewControllerDidFinish:方法。
目前来说我们的文件还不是特别长。只要通过浏览整个文件就能找到想要的方法。不过,使用编辑器的跳转工具条会简便很多(见图1.28)。
现在,让我们来修改flipsideViewControllerDidFinish: 方法吧!
- (void)flipsideViewControllerDidFinish:
(HWFlipsideViewController *)controller
{
******self.label.text = controller.labelText.text;**
[self dismissModalViewControllerAnimated:YES];
}
正如我们之前所讨论的,这一行只是使用输出口和属性将文本值从背面视图文本字段拷贝到主视图的标签中。
完成了,再次运行应用。启动后应该会显示默认的Hello World消息。点击info按钮,并且在文本字段中输入新的文本。点击Done按钮,主视图的标签就会显示你刚才输入的新文本了。
1.4.4 改善界面
从功能上来说,一切正常,但是还没有成为世界上最完美(或者,就这个示例来说,有用的)的应用程序。让我们来让它变得更好一点!当背面视图显示时,我们用标签现有值来填充文本字段。此外,我们修改成当用户点击回车键时就关闭背面视图。
首先,让我们把主视图的标签文本传递给背面视图。理想地来说,我们会在prepareForSegue:sender:方法中设定这个值。这应该是flipsideViewControllerDidFinish:方法的逆向代码;我们从主视图标签中将文本值直接拷贝到背面视图中的文本字段。不妙的是,由于视图加载的方式,文本字段目前可能还不存在。要完成这个操作有几个方法。让我们给HWFlipsideViewController类添加一个属性用来保存我们的文本,直到我们确定这个视图可以运行了。
打开HWFlipsideViewController.h文件并且在其他属性后添加下面这一行:
@property (nonatomic, strong) NSString* startingText;
在HWFlipsideViewController.m文件中,我们需要实现(synthesize)这个属性(在第2章的“属性”一节查看更多信息)。在@implementation程序块的开始添加下面这一行:
@synthesize startingText = _startingText;
现在,滚动屏幕到viewWillLoad``:方法并且按照下面所示修改它:
- (void)viewWillAppear:(BOOL)animated
{
self.labelText.text = self.startingText;
[super viewWillAppear:animated];
}
这个方法每次在背面视图出现时就会被调用。这里,我们只是将储存在startingText属性的值赋值给文本字段。接着,再次打开HWMainViewController.m文件。按照下面所示修改prepareFor
Segue:sender``:方法。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showAlternate"])
{
id flipsideViewController =
[segue destinationViewController];
[flipsideViewController setDelegate:self];
[flipsideViewController setStartingText:self.label.text];
}
}
由于我们要设置多个属性,为了减少代码量,我们获取HWFlipside
ViewController的一个引用。然后像之前所说的使用这个引用来设置委托。最终,把主视图中标签的文本字符串保存在startingText属性里。
安全地访问视图控制器的输出口
在这个例子中,直到系统完全加载了视图后,我们才能修改文本字段的内容。我们将会在第3章和第4章中更深入地讨论这一点。不过,先简单地解释一下,UIkit不会在创建视图控制器时立即加载视图,而是等到实际需要视图的时候再加载(通常是在系统要在屏幕上显示视图时)。UIKit是由于性能的原因才这么做,如果你不注意的话将会导致非常令人困惑的错误。
典型的情况是,这些错误会在你对视图控制器的输出口做一些编程修改时出现,尤其当输出口是由Interface Builder创建时。当你运行应用程序时,代码被触发了,修改的内容看上去并没生效。 无论什么时候出现这个情况了,仔细检查确保输出口真正已经存在,这样的话它应该会有一个非零的值。如果不是,你需要延迟输出口的设置代码,正如我们这里所做。
完成了一点改进,现在开始下一点改进。再次打开Assistant editor,左边是storyboard,右边是HWFlipsideViewController.h文件。我们要将文本字段的Did End On Exit事件和控制器的done: 方法连接起来。有几个方法可以完成这个连接。例如,我们可以按住Control键并拖动文本字段到done: 方法上。不妙的是,这样做不允许我们选择事件,它会自动连接Editing Did End事件,而不是Did End On Exit事件。
正确的操作是,按住control键然后点击文本字段,就会打开Connections对话框。点击并且拖动Did End On Exit事件的右侧圆圈到done: 方法上,如图1.30所示。
还有另外几个等效的替代方法。你可以按住Control键再点击场景底部工具条中的HWFlipsideViewController图标,然后拖动done:操作到文本字段上。Xcode会提示你选择正确的事件。同样你也可以使用实用工具区的Connections inspector,而不使用弹出对话框。所有这些方法都是等效的。你可以多尝试不同的方法,看看哪一种方法最适合自己。
注意:
每个事件只能与一个操作相连,但是一个操作可以和多个事件连接。在这个示例中,文本字段和Done按钮都是和done:操作相连的。
既然说到这里,就让我们来改变键盘Return键的外观。选中文本字段并且打开Attributes inspector。将Return Key属性设置为Done。虽然这不会改变键盘的功能,但是却有助于传达我们的意图。
你可能还想要设置Clear Button属性为“Appears while editing”。毕竟,使用退格键来删除大量的文本方式是令人讨厌的。
完成了。现在运行这个应用程序吧!显示效果应该如图1.31和图1.32所示。
注意:
虽然Xcode在自动选择正确的配套文件方面的功能很强大,但是有时候也可能会出错,或者你想要选择另外一个文件。你可以在跳转工具条中完成这个操作。选中叶项目,你就能以大致相同的挑选规则选择一个替代文件。选中根项目,你就可以选择不同的挑选规则。Xcode提供了一些不同的视具体环境而定的挑选规则。如果必要的话,你也可以手动选择配套文件。
Xcode将会对HWMainViewController.h文件、HWMainView Controller.m文件和MainStoryboard.storyboard文件做一些改变。在头文件中,它声明了我们的标签的属性。
import "HWFlipsideViewController.h"
@interface HWMainViewController : UIViewController
<HWFlipsideViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UILabel *label;
@end
在实现文件中,Xcode生成我们的标签属性,并且在视图卸载的时候把它设置为nil。这有助于释放不再需要的内存。
#import "HWMainViewController.h"
@implementation HWMainViewController
@synthesize label;
....
- (void)viewDidUnload
{
[self setLabel:nil];
[super viewDidUnload];
// 释放主视图保留的任何子视图
// 例如 self.myOutlet = nil;.
}
在storyboard文件中,Xcode连接了标签和新创建的输出口。你可以通过Connection inspector来查看这些连接。此外,按住Control键点击主视图控制器图标,也可以打开连接对话框(见图1.27)。