iPhone开发基础教程笔记(三)--第四章 更丰富的用户界面

第四章 更丰富的用户界面

我们将实现一个图像视图、一个滑块、两个不同的文本字段、一个分段控件、一些开关和一个更符合iPhone风格的按钮。

你将学习如何使用视图层次结构对公共父视图下的多个项目进行分组,以及如何在运行时更加轻松地操作界面。

你将了解如何设置和检索各种控件中的值,这可以使用输出口或使用操作方法的sender参数来完成。

然后,我们将介绍如何使用操作表强制用户作出选择,并向用户显示重要反馈。

我们还将介绍控件状态,以及如何使用可拉伸图像让按钮的显示效果更加美观。

我们会将应用程序分成若干个小块,每次实现其中的一块,你将往返于XcodeInterface BuilderiPhone仿真器之间。这样可以

简化它,并且更加接近于实际的应用程序构建流程。这种“编码-编译-调试”周期是软件开发人员日常工作的主要组成部分。

4.1 满是控件的屏幕

我们将构建的视图中的元素更加丰富。

iPhone屏幕顶部的徽标是一个“图像视图”。他的作用仅仅是显示一个静态图像。

徽标下发是两个“文本字段”,一个允许输入字母和数字形式的文本,另一个只允许输入数字。

位于文本字段下方的是一个“滑块”。当用户更改滑块时,其左侧标签的值会随之更改。

滑块下发是一个“分段控件”和两个“开关”。分段控件将根据选中的是Show还是Hide来显示或隐藏两个开关。更改任一开关的值

都会导致另一个开关更改其值,以与之匹配。

开关下发是一个Do Something按钮,该按钮用于弹出一个操作表,询问用户是否确定要单击按钮。这是响应具有潜在危险或导致严

重后果的输入的标准方式。确认后,应用程序将使用警告通知用户是否一切正常。

4.2 活动、静态和被动控件

用户界面控件共有3种基本形式:活动、静态和被动。

按钮一般是活动的

标签一般是静态的,图像也是,只能通过代码修改,用户不能修改,但这两者都是UIControl的子类,并且可以用他们触发特定的代

码。

一些控件可以在被动方式下运行,仅用于存储用户输入的值,直到用户完成为止。这些控件不触发任何操作方法,但用户可以与之

交互,并修改他们的值。

文本字段是被动控件的典型例子。虽然可以在移出字段时触发验证代码,但网页上的大多数文本字段都只是用作保存数据的容器,

这些数据在用户单击提交按钮时被提交给服务器。文本字段自身不触发任何代码,但是单击提交按钮时,文本字段的数据将可以传

递。

iPhone上,许多可用控件都可以通过这3种方式加以使用,并且大多数控件的功能都不是唯一的。

所有iPhone控件都是UIControl的子类,因此他们能够触发操作方法。大多数控件还可以被动使用,并且他们都可以在创建时被设定

为非活动,或者在运行时从非活动改为活动。但是,包括按钮在内的一些控件,除了在活动方式下用来触发代码以外,实际上并没

有其他用途。

iPhoneMac上的控件在行为上存在一些差异。由于多点触摸界面的引入,所有iPhone控件都可以根据其接触方式触发多种操作:用

户可以通过触碰按钮来触发一个操作,也可以通过滑触动作来触发不同的操作。你还可以让用户按下按钮时触发一个操作,当用户

手指离开按钮时触发另一个操作。相反,也可以让单个控件对单一事件调用多个操作方法。可以让Touch Up Inside事件触发两个不

同的操作。

iPhoneMac之间的另一个主要区别是,iPhone没有物理键盘。代码可能永远都不会直接与iPhone键盘交互,但有时需要编写代码让

键盘行为符合开发人员的需求。

4.3 创建应用程序

创建一个名为Control Fun的新项目,仍然使用View-Based Application模版选项。

4.3.1 导入图像

创建项目之后,找到将在图像视图中使用的图像。需要将图像导入到Xcode中,然后才能使用。确保图像格式为.png,且大小不超过

可用的空间。高度小于100px,宽度小于300px,以适应视图布局,而不需要重新调整大小。

将图像添加到项目的Resources文件夹。

4.3.2 实现图像视图和文本字段

1.确定输出口

在使用Interface Builder之前,我们需要确定哪些对象需要输出口。记住,需要在控制器类的头文件中定义输出口,然后才能将他

们连接到Interface Builder中的任何对象。

图像视图只是一个静态图像,并且不需要更改,所以他不需要输出口。如果需要更改他,则需要一个输出口。

对于两个标签也是如此。

另一方面,两个文本字段则需要输出口。请自行添加(名称分别为nameFieldnumberField)及其相应属性到

Control_FunViewController.h类文件中。如下所示:

#import <UIKit/UIKit.h>

@interface Control_FunViewController:UIViewController {

 IBOutlet UITextField *nameField;

 IBOutlet UITextField *numberField;

}

@property (nonatomic,retain) UITextField *nameField;

@property (nonatomic,retain) UITextField *numberField;

@end

在转向Interface Builder之前,还需要将@synthesize指令添加到Control_FunViewController.m中:

#import "Control_FunViewController.h"

@implementation Control_FunViewController

@synthesize nameField;

@synthesize numberField;

...

2,确定操作

回顾一下上面的5个对象,是否发现需要声明某个操作呢?图像视图和标签不支持与用户交互,不能接受触摸,因此不需要为他们指

定操作,对吗?没错,就是这样。

那么两个文本字段也是这样吗?我们不需要对这些字段执行任何验证,因此不需要为他们指定操作。

3,构建界面

打开Resources下的Control_FunViewController.xib来启动IB。找到库中的Image View

4.3.3 添加图像视图

拖动一个图像视图到View窗口上。由于这是在视图上放置的第一个项,因此IB将自动重新调整图像视图的大小,使他与视图的大小

保持一致。由于我们不希望图像视图占用这个空间,因此,使用拖动手柄将图像视图的大小重新调整为与导入Xcode的图像相近的大

小。不要担心很难做到精确无误,过一会你会发现,其实是很容易做到的。

顺便说一下,有些取消选中的对象很难再次选中,因为他们位于另一个对象的后面,占用了整个视图,或者没有绘制边框。对于这

些情况,完全不用担心!有一种方法可以重新选中这些对象。在nib的主窗口中,可以看到3个标签为View Mode的按钮。单击位于中

间的按钮,可以得到nib的分层视图,你可以展开其中的子视图。双击此视图中的任何项目就可以在View窗口中选中同一项目。

选中图像视图之后,按Cmd+1调出检查器,应该能看到UIImageView类的可编辑选项。

图像视图中重要的设置就是位于检查器最顶部的Image属性。如果单击该字段右侧的小箭头,则会弹出一个菜单并显示可用的图像,

其中应包括添加到Xcode项目中的任何图像。

1,调整图像视图

现在,调整图像视图,使他与图像大小完全保持一致。按Cmd+=或从Layout菜单中选择Size to fit。此选项将自动调整任何视图的

大小,使他适应所包含的内容。我们还希望图像居中,且顶部与蓝色引导线对齐。从Layout菜单的Alignment子菜单中选择Align

Horizontal Center in Container,这样可以方便地将视图中的项居中。

提示:在IB中拖动和重新调整视图需要一些技巧。不要遗忘了nib主窗口中的分层View Mode按钮。他将帮助你找到并选中(双击)

图像视图。在重新调整视图大小时,可以按下Option键。IB将在屏幕上绘制一些有用的红线,以便开发人员掌握图像视图的大小。

此技巧不适用于拖动操作。在这种情况下,Option键将通知IB创建你正在拖动的对象的副本。

2.Mode属性

图像视图检查器中的下一个选项是Mode下拉菜单。Mode菜单用于定义图像在视图内部的对齐方式,以及是否缩放以适应视图。记住

,选择任何让图像缩放的选项都会潜在地增加处理开销,因此最好避免这些选项,并在导入图像之前调整好他们的大小。如果希望

以多种大小显示同一图像,通常,更好的方式是在项目中为该图像创建不同大小的多个副本,而不是强制iPhone在运行时对它们执

行缩放。

3Alpha滑块

检查器中的下一项是Alpha。除非有足够的理由,否则一般将该值设置为1.0,否则会增加开销。

4,忽略Background
5Tag属性

尽管这里不使用他,但是他值得注意。UIView的所有子类,包括所有视图和控件,都有一个标记属性,该属性只是与图像视图绑定

在一起的一个数值。标记是供开发人员使用的,系统永远不会设置或修改他的值。如果为某控件或视图分配了一个标记值,则可以

确定的是,该标记始终为这个值,除非你又修改了他。

6Drawing复选框

Tag下方有一系列Drawing复选框。第一个复选框的标签为Opaque。选中它。这将通知iPhone OS,视图下的任何内容都不应绘制,并

且运行iPhone的绘图方法通过一些优化来加速绘图。

你可能想知道为何需要选中Opaque复选框,因为Alpha的值已经设置为1.0(不透明)。其原因是,Alpha值适用于将被绘制的图像部

分,但是,如果某个图像未完全填充图像视图,或者图像上存在一些洞(由Alpha通道或剪贴路径所致),则其下发的图像将仍然可

见,而与Alpha值无关。选中Opaque复选框之后,iPhone就会知道视图下发的任何内容都不需要绘制出来。我们可以放心地选中

Opaque复选框,因为我们之前选中了Size to Fit,该选项使图像视图与他所包含的图像大小相匹配。

Hidden复选框的作用显而易见。选中他之后,用户将不能看见此控件。

Clip Subviews是一个有趣的选项。如果你的视图有子视图,并且这些子视图并不是完全包含在其父视图之内,则此复选框将确定子

视图的绘制方式。如果选中,只有在父视图之内的子视图部分才被绘制出来。看上去,默认启用Clip Subviews,但是这样比较占用

资源,并且一般情况下,子视图不会位于父视图的外部。处于性能的考虑,他在默认情况下应该是关闭的。

下一个复选框是很少需要选中的Clear Context Before Drawing。选中他之后,iPhone将使用透明黑色绘制控件覆盖的所有区域,

然后才实际绘制控件。考虑到性能问题,并且适用情况很少,他默认为关闭状态。

7Interaction复选框

最后两个复选框与用户交互有关。第一个复选框User Interaction Enabled指定用户能否对此对象进行操作。对于大多数控件,此

复选框是选中的。但是,标签和图像视图默认未选中。

最后一个复选框是Mutiple Touch,用于确保此控件是否能够接收多点触摸事件。如用于缩放等操作。这里将它保留为默认值即可。

4.3.4 添加文本字段

完成图像视图添加之后,从库中拖出一个文本字段并将其移动到View窗口上。将他放置在图像视图下发,需要使用蓝色引导线保持

他与右边缘对齐。显示与图像视图的接近程度的水平蓝色引导线应该看作文本字段与图像视图之间的最短距离。你可以不改动他,

但是为了获得更加平衡的外观,将它下移一点会比较好。记住,你随时可以回到IB中修改界面元素的位置和大小,而不需要修改代

码或重新建立连接。

放置好文本字段之后,从库中拖出一个标签,移动他,使他与视图左侧对齐,并与之前放置的文本字段垂直对齐。注意,移动标签

时会弹出多条蓝色引导线,这样便可以使用顶部、底部、中间或文本基准引导线来对齐文本字段与标签。

双击刚才放置的标签,进入编辑状态,输入"name:"作为标签名,然后按回车键提交更改。

接下来从库中拖出另一个文本字段和标签。移至适当的位置,并编辑标签文本为"Number:"

最后,选中顶部的“文本字段”,按Cmd+1打开检查器。

1,文本字段设置

文本字段是iPhone上最复杂和最常用的控件之一。

首先看检查器最顶部的区域,在第一个字段Text中,可以设置其默认值。

第二个字段是placeHolder,他用于指定将文本字段中以灰色显示的文本,前提是字段没有值。如果空间不足的话,可以使用占位符

来代替标签,或者使用他告诉用户应在此字段中键入的值。这里我们键入“Type in a name”做为占位符。

接下来的两个字段仅在需要定制文本字段的外观时使用,多数情况下,完全不必要也不建议使用他们。因此,我们掠过Background

Disabled字段,并将他们保留为空。

位于这些字段下方的是3个按钮,用于控制字段中文本的对齐方式。这里保留默认值--左对齐。该按钮旁边的字段可用于指定文本颜

色。

接下来是4Border按钮。用于更改文本字段边缘的绘制方式。可以任意尝试,但建议保留默认值。

Clear When Editing Begins 复选框指定用户触摸此字段时的操作,如果选中,则之前该字段中的任何值都将被删除。

Adjust to Fit复选框指定文本的大小是否应随文本字段尺寸的减小而减小。此选项确保整个文本视图都可见,即使文本大于所分配

的控件。此复选框的右侧是一个文本字段,用于指定最小文本大小。无论字段大小如何,文本都将跟均此最小值进行调整。指定最

小值可以确保文本不会因为过小而影响可读性。

2,文本输入特征

接下来的部分定义在使用此文本字段时键盘的外观及行为。由于我们预期的文本是姓名,因此将Capitalize下拉列表更改为Words

此选项将所有单词自动转换为首字母大写。此外,将Return Keys弹出项的值更改为Done,并将所有其他文本输入特征保留为默认值

3,其他设置

接下来的部分用于设置继承自UIControl的一般控件属性,但他们通常不适用于文本字段,并且,除Enabled之外的所有复选框都不

会影响字段的外观。因此,保留默认设置

检查器的最后一部分你应该比较熟悉了,因为这是UIView类的属性,所有控件都是继承UIView的,所以,他们都具有这部分的属性

。注意,对于文本字段,你不需要选中Opaque,因为这样会让输入的文本不可见。

4.3.5 设置第二个文本字段的属性

设置PlaceHolder属性为"Type in a number"

取消Clear When Editing Begins

Text Input Traits部分中,单击Keyboard Type弹出菜单,选中Number Pad。不需要为数字键盘设置Return Key值,因为这种样

式的键盘没有回车键

4.3.6 连接输出口

按下Ctrl键,从File's Owner拖动到各文本字段,然后将他们连接到相应的输出口。

4.4 构建和运行

接下来看看应用程序的运行情况。从Build菜单中选择Build and Run

有一个小问题,应该如何关闭键盘界面呢?

4.4.1 完成输入后关闭键盘

当用户按下Done按钮时,将生成一个“did end on exit”事件,此时,我们需要告诉文本字段取消控件,以关闭键盘。为此,我们

需要在控制器类中添加一个操作方法:

- (IBAction)textFieldDoneEditing:(id)sender;

其实现代码:

- (IBAction)textFieldDoneEditing:(id)sender

{

 [sender resignFirstResponder];

}

我们之前已经提到first Responder的概念。此处,我们告诉触发此操作的任何控件取消第一响应者状态。当文本字段生成第一响应

者状态之后,与之相关的键盘将消失。

别忘了保存。返回IB,并通过这两个文本字段触发此操作。

返回IB之后,单击Name文本字段,然后按Cmd+2调出连接检查器。这一次,我们不需要设置第三章所使用的Touch Up Inside事件。

而应采用Did End on Exit事件,该事件将在用户单击iPhone键盘上的Done按钮时被触发。从Did End on Exit旁边的圆圈拖动到

File's Owner图标,并将他连接到textFieldDoneEditing:操作。对其他文本字段重复上述步骤,然后保存。

再次构建并运行应用程序。

Done时,键盘在意料之中消失。那么Number字段也是这样吗?可是该字段的Done按钮在哪里呢?并非所有的键盘布局都有Done

钮。我们可以通过让用户在视图中任何无活动控件的位置按下手指,让键盘消失。应如何实现此功能呢?只需要创建一个不可见的

按钮,将其置于其他所有元素后面,用于通知文本字段在检测到触摸操作时生成第一响应者状态。

4.4.2 通过触摸背景关闭键盘

返回Xcode。我们需要在控制器类中再添加一个操作。将以下行添加到Control_FunViewController.h文件中:

- (IBAction) backgroundClick:(id)sender;

其实现:在非第一响应者控件上调用resignFirstResponder是绝对安全的,因此我们可以放心地对两个文本字段调用他,而不需要

检查哪一个才是第一响应者。

- (IBAction) backgroundClick:(id)sender

{

 [nameField resignFirstResponder];

 [numberField resignFirstResponder];

}

提示:在编写代码时,你将在头文件与实现文件之间来回切换。幸运的是,Xcode提供了一个组合键,用于在这些文件之间快速来回

切换。默认的组合键为Option+Cmd+↑,但你可以在Xcode的首选项中任意更改他们。

保存此文件。返回IB,我们现在创建那个非常神秘的不可见按钮,该按钮将调用backgroundClick:操作。从库中拖一个Round Rect

Button到视图窗口中。使用按钮边缘的调整点让他充满整个屏幕。这次不要在蓝色边缘线的位置停止,而是继续拖动到边缘外部,

不要担心他会覆盖视图中的其他项目。如果要将此按钮置于其他所有元素后面,就从Layout菜单中选择Send to Back

现在仍然选中这个新按钮,按Cmd+1调出检查器,并将按钮类型从Rounded Rect更改为Custom

按钮应基本处于不可见状态,除了边缘附件的调整点。Custom选项经常用于覆盖按钮的默认外观。但是,他也适用于没有外观的按

钮。本例就是这种情况。

现在按Cmd+2切换到连接检查器,然后设置该按钮的Touch Up Inside事件为backgroundClick:操作。现在,触摸视图中没有活动控

件的区域都将触发这个新操作方法,从而关闭键盘。

保存nib文件,返回Xcode并编译运行程序。查看效果!!

4.5 实现滑块和标签

4.5.1 确定输出口

我们将在界面中添加另外两个项。想知道我们究竟需要多少输出口吗?我们需要编写代码让标签随滑块的变化而变化,因此标签只

需要一个输出口。那么滑块呢?

滑块将触发一个操作,随后,该操作方法将通过sender参数接收一个指向滑块的指针。我们能够从sender中检索滑块的值,因此我

们不需要通过输出口来获得滑块的值。那么,滑块是否完全不需要输出口呢?换句话说,我们需要在滑块将调用的操作方法外部访

问滑块的值吗?

在实际的应用程序中,经常需要这样做。此处,由于另一个控件将与滑块拥有相同的值,并且已经有了一个输出口,因此没有必要

为滑块本身再定义一个输出口。编写iPhone应用程序时需要考虑内存。虽然指针占用的内存很小。

4.5.2 确定操作

这两个控件的操作非常简单。

4.5.3 添加输出口和操作

Control_FunViewController.h文件中再声明一个输出口和一个操作。如下所示:

IBOutlet UILabel *sliderLabel;

@property (nonatomic,retain) UILabel *sliderLabel;

- (IBAction) sliderChanged:(id)sender;

实现:

- (IBAction) sliderChanged:(id)sender

{ UISlider *slider=(UISlider *)sender;

 int progressAsInt=(int)(slider.value+0.5f);

 NSString *newText=[[NSString alloc] initWithFormat:@"%d",progressAsInt];

 sliderLabel.text=newText;

 [newText release];

}

4.5.4 添加滑块和标签

打开Control_FunViewController.xib,从库中拖出一个滑块,将其放置在Number文本字段下方,让他占用大部分(而不是全部)水

平空间。在左侧留点空间给标签。

选中滑块控件,按Cmd+1打开检查器。

用户可以通过滑块选择特定范围内的数值。此处,我们在IB中设置滑块范围和初始值。输入1作为最小值,100作为最大值,50作为

初始值。目前只需要了解这些设置。

在滑块左侧放置一个标签,使用蓝色引导线使其保持与滑块垂直对齐,并保持左侧边缘与视图的左侧边缘对齐。

设置标签文本为100.这是滑块的最大值,并且可以使用他确定滑块的正确宽度。由于“100”比“Label”短,因此应该调整标签的

大小,方法是将正中间的调整点向左拖动。确保不要让文本变小,如果他开始变小,应将 调整点往回拖一点,回到原来的位置。还

可以使用之前讨论的Size to Fit选项,方法是按Cmd+=或从Layout菜单中选择Size to Fit

接下来调整滑块的大小,单击滑块并将其左侧调整点向左拖动,直到蓝色引导线靠齐。

现在,再次双击标签,将其值改为50.

4.5.5 连接操作和输出口

设置滑块的Value Changed事件的操作为sliderChanged:方法。

注意:如果按下Ctrl键并从File's Owner拖动到界面上的项时,选不到sliderLabel项,可以按Cmd+2打开连接检查器,并从输出口

旁边的小圆圈拖动到要连接的对象。

 

4.6 实现开关和分段控件

我们将要在应用程序添加两个开关和一个分段控件。这种小控件仅有两种状态:开和关。

4.6.1 确定输出口

我们不希望为分段控件指定输出口,因为我们不会修改其属性或在其调用的操作方法外部引用他。但是,我们需要为开关指定一些

输出口。由于更改任一开关的值都会影响到另一个开关的值,因此我们更改未触发操作方法的开关的值,从而不会依赖sender。我

们还需要另外一个输出口,用于将添加的另一个视图。记住,我们将在触摸分段控件时隐藏或显示这些开关以及他们的标签。

4.6.2 确定操作

分段控件需要触发一个操作方法,用于隐藏或显示开关以及标签的视图。我们还需要在触摸开关时触发一个操作。这两个开关将调

用相同的操作方法。在Control_FunViewController.h中,添加3个输出口和两个操作:

#define kShowSegmentIndex 0

IBOutlet UISwitch *leftSwitch;

IBOutlet UISwitch *rightSwitch;

IBOutlet UIView *switchView;

@property (nonatomic,retain) UISwitch *leftSwitch;

@property (nonatomic,retain) UISwitch *rightSwitch;

@property (nonatomic,retain) UIView *switchView;

- (IBAction)switchChanged:(id)sender;

- (IBAction)toggleShowHide:(id)sender;

在即将编写的代码中我们将引用一个UISegmentedControl属性,即selectedSegmentIndex。该属性告诉我们当前选中的是哪一个分

段。他是一个整数值。Show分段的索引将为0.我们在代码中将其定义为kShowSegmentIndex常量,而不是直接使用0值,从而让代码

更具有可读性。

切换到Control_FunViewController.m,实现方法:

@synthesize leftSwitch;

@synthesize rightSwitch;

@synthesize switchView;

- (IBAction)switchChanged:(id)sender

{ UISwitch *whichSwitch=(UISwitch *)sender;

 BOOL setting=whichSwitch.isOn;

 [leftSwitch setOn:setting animated:YES];

 [rightSwitch setOn:setting animated:YES];

}

- (IBAction)toggleShowHide:(id)sender

{ UISegmentedControl *segmentedControl=(UISegmentedControl *)sender;

 NSInteger segment=segmentedControl.selectedSegmentIndex;

 

 if (segment==kShowSegmentIndex) [switchView setHidden:NO];

 else [switchView setHidden:YES];

}

toggleShowHide:中,我们查看当前选中的分段,并显示或隐藏UIViewUIView是需要隐藏的所有对象的父视图。一些特定的属性

是从父视图继承而来的,因此如果某个视图为隐藏状态或被禁用,则该视图的所有子视图也将隐藏或被禁用。

4.6.3 添加开关和分段控件

从库中拖出分段控件,并将它放置在View窗口的滑块的下方。

扩展分段控件的宽度,使他从视图左侧拉伸到右侧。将光标移动到分段控件的First单词上,然后双击他。分段的标题将变为可编辑

状态。将First更改为“Show”。将Second更改为“Hide”。

1,添加另一个视图

从库中再拖出一个视图,并将它放置在View窗口中的分段控件的正下方。默认情况下,UIView元素未被绘制出,但这不会影响界面

的外观。他只是一个用于保存其他视图的容器。但是,我们可以更改视图的背景颜色,使他可见并且更易于操作。你可以在检查器

中更改新视图的背景色,我们选择的是浅灰色。

如果在设置背景色之前未选中视图,那么可以通过一个小技巧来找到他并帮助你设计视图。按下Option键,将光标移动到View窗口

中。当光标移动到某个对象上时,他将突出显示为红色。你还可以看出项与其父视图之间距离多少像素。

2,添加两个带标签的开关

从库中拖出一个开关,将其放置在刚才添加到窗口中的视图中。记住,你需要确保将开关添加为新视图的子视图,且在释放鼠标之

前能够看到一个灰色的View框和一个绿色的加号图标。对第二个开关重复此步骤。现在,同样以子视图方式添加两个标签。在各开

关上方分别放置一个标签,并将左侧标签的值更改为Left,右侧标签的值更改为Right

提示 在IB中,可以按下Option键拖动对象,这样会创建对象的副本。如果要创建同一对象的多个实例,只需从库中拖出一个对象,

然后按Option键并拖动对象即可。

4.6.4 连接输出口

将开关的Value Changed事件指向File's OwnerswitchChanged:方法。

 

4.7 实现按钮、操作表和警报

4.7.1 将输出口及操作添加到控制器头文件

除了输出口和操作之外,头文件中还有一个要求:我们的类必须符合UIActionSheetDelegate协议。当用户按下按钮时,程序将向他

们显示一个“操作表”,询问是否确定要继续。当用户按下一个操作表按钮时,表会消失,并调用一个方法告诉我们按钮已经被按

下。为了接收操作表中的消息,我们需要符合UIActionSheetDelegate协议,并实现该协议中的一个回调方法。操作表是“模式化”

的,这意味着当程序显示他们时,用户不能与应用程序的任何其他部分交互。因此,我们基本上是在强制用户作出决定,然后才能

执行其他操作。

添加到Control_FunViewController.h中的代码如下:

...

@interface Control_FunViewController:UIViewController <UIActionSheetDelegate> {

 ...

 IBOutlet UIButton *doSomethingButton;

}

...

@property (nonatomic,retain) UIButton *doSomethingButton;

- (IBAction)doSomething:(id)sender;

@end

4.7.2 IB中添加那妞

从库中拖出一个Round Rect Button,并将其放置在视图中。双击该按钮,将其标题设置为Do Something。接下来,按下Ctrl键并从

File's Owner图标拖到该按钮,并将其连接到doSomethingButton输出口。然后,将Touch Up Inside事件连接到doSomething:操作

4.7.3 实现按钮的操作方法

Control_FunViewController.m文件更改如下:

...

@synthesize doSomethingButton;

- (IBAction)doSomething:(id)sender

{ UIActionSheet *actionSheet=[[UIActionSheet alloc]

    initWithTitle:@"Are you sure?"

    delegate:self

    cancelButtonTitle:@"No Way"

    destructiveButtonTitle:@"Yes,I'm sure!"

    otherButtonTitles:nil];

  [actionSheet showInView:self.view];

  [actionSheet release];

}

- (void)actionSheet:(UIActionsheet *)actionSheet

 didMismissWithButtonIndex:(NSInteger)ButtonIndex

{

  if (!buttonIndex==[actionSheet cancelButtonIndex])

  {

    NSString *msg=nil;

    if (nameField.text.length>0)

     msg=[[NSString alloc] initWithFormat:@"You can breathe easy,%@,everything went OK.",nameField.text];

    else

     msg=@"You can breathe easy,everything went ok.";

 

    UIAlertView *alert=[UIAlertView alloc] initWithTitle:@"Something was done"

         message:msg

         delegate:self

         cancelButtonTitle:@"Phew!"

         otherButtonTitles:nil];

    [alert show];

    [alert release];

    [msg release];

 }

}

4.8 显示操作表

首先看一下doSomething:方法。该方法的确切作用是什么?我们首先分配并初始化一个UIActionSheet对象,该对象表示一个操作表

 UIActionSheet *actionSheet=[[UIActionSheet alloc]

    initWithTitle:@"Are you sure?"

    delegate:self

    cancelButtonTitle:@"No Way"

    destructiveButtonTitle:@"Yes,I'm sure!"

    otherButtonTitles:nil];

初始化方法的参数介绍:

第一个参数表示标题

delegate是操作表的委托。操作表的委托将在该表上的按钮被按下时收到通知。更确切地说,委托的

actionSheet:didDismissWithButtonIndex:actionSheet:didDismissWithButtonIndex:方法将被调用。

cancelButtonTitle表示取消按钮的标题。如果不让用户作出选择,则警报会比较合适。我们将在稍后讲解警报

destructiveButtonTitle表示确定按钮的标题

otherButtonTitles用于指定在表单上显示的其他按钮的数量。该参数可以使用各种值,这是Obj-C语言中的一个非常好的特性。如

果我们希望操作表上还有另外两个按钮,可以编写如下代码:

 UIActionSheet *actionSheet=[[UIActionSheet alloc]

    initWithTitle:@"Are you sure?"

    delegate:self

    cancelButtonTitle:@"No Way"

    destructiveButtonTitle:@"Yes,I'm sure!"

    otherButtonTitles:@"Foo",@"Bar",nil];

你可以在otherButtonTitles参数中传递任意数量的变量,只要以nil做为最后一个变量传递即可。但根据可用屏幕空间的大小,按

钮的数量将受到实际限制。

创建操作表之后,我们让他显示。在iPhone上,操作表始终有一个父视图,即当前对用户可见的视图。在本例中,我们希望使用在

Interface Builder中设计的视图做为父视图,因此使用self.viewview是父类UIViewController的一个属性,他指向该类的控制

器所对应的视图。

最后,我们将释放操作表。不必担心,此操作在用户按下按钮之后才会执行。

操作表委托和创建警报

- (void)actionSheet:(UIActionsheet *)actionSheet didMismissWithButtonIndex:(NSInteger)ButtonIndex

参数buttonIndex可以告诉我们实际按下的是哪个按钮。但是,我们如何才能知道哪个按钮索引指向取消按钮或其他按钮呢?别忘了

actionSheet参数对象,这个对象知道哪个按钮是取消按钮。

if (!buttonIndex==[actionSheet cancelButtonIndex]) 这就是如果按钮不是取消按钮的比较表达式。

下面是创建警报表的语句,和创建操作表非常相似:

 UIAlertView *alert=[UIAlertView alloc] initWithTitle:@"Something was done"

         message:msg

         delegate:self

         cancelButtonTitle:@"Phew!"

         otherButtonTitles:nil];

警报表同样有委托,实现此委托需要遵守UIAlertViewDelegate协议。

显示警报并没有与特定视图绑定在一起。因此,我们仅需显示警报,而不用指定父视图。

 

4.9 美化按钮

你可能注意到,Do Something按钮的外观与其他按钮的外观不一样。这是因为默认Round Rect Button按钮的外观本来就不太好,因

此我们最后再稍微处理一下该按钮。

iPhone中的大多数按钮都是使用图像绘制的。你不用自己去创建图像,只需要指定iPhone在绘制按钮时所使用的模版图像类型。

需要记住,你的应用程序是沙盒化的。你要确保你所需要的图像都位于自己应用程序的束中。那么,怎么获取这些图像模版呢?

好在苹果公司提供了一个束。你可以从iPhone示例应用程序UICatalog中获取他们,地址为:

http://developer.apple.com/iphone/library/samplecode/UICatalog/index.html

苹果公司的示例代码许可证特别允许你使用和分发他们。

IB中,修改Do Something按钮的类型,从Round Rect修改为Custom。在检查器中,你可以为按钮指定图像,但我们并不会这么做,因此这些图像模版需要采用稍微不同的处理方式。保存nib,然后返回Xcode

4.9.1 viewDidLoad方法

如果需要修改在nib中创建的任何对象,我们可以重写控制器父类UIViewController中的viewDidLoad方法。由于在IB中并不能完成一切任务,因此我们将利用viewDidLoad方法。将以下代码添加到Control_FunViewController.m文件中。

- (void) viewDidLoad

{ jmUIImage *buttonImageNormal=[UIImage imageNamed:@"whiteButton.png"];

 UIImage *stretchableButtonImageNormal=[buttonImageNormal stretchableImageWithLeftCapWdith:12 topCapHeight:0];

 [doSomethingButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

 UIImage *buttonImagePressed=[UIImage imageNamed:@"blueButton.png"];

 UIImage *stretchableButtonImagePressed=[buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];

 [doSomethingButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];

}

此代码根据添加到项目中的模版图像为按钮设置背景图像。他指定按钮被触摸时应从白色图像转换为蓝色图像。这个简短的方法引入了两个概念:控制状态和可拉伸图像

4.9.2 控件状态

每个iPhone控件都有4种不同的状态:普通状态、突出显示状态、禁用状态、选中状态。

4.9.3 可拉伸图像

可拉伸图像是可调整大小的图像,他知道如何智能地重新调整其大小,以维持正确的外观。对于这些按钮模版,我们不希望边缘也被均匀拉伸。端帽(end cap)是一个图像的一部分,以像素为单位进行度量,他就不应该被调整。我们希望边缘保存原样,而与按钮的大小无关,因此我们将左侧端帽的大小设置为12

提示:我们应该如何确定端帽的值呢?非常简单:我们复制了苹果公司的示例代码。

4.10 小结

学习完这一章,你应该熟悉了输出口和操作的实际用法,并了解了如何利用视图的分层属性。你学习了控件状态和可拉伸图像,以及如何使用操作表和警报表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值