21.4 表示层开发
从客观上讲,表示层开发的工作量是很大的,工作要做得很细致。
21.4.1 添加图片资源
首先需要把应用中要用的图片等资源添加到工程中。具体步骤如图21-13所示,右键选择Supporting Files组,选择菜单中的Add Files to “Calculator”…弹出选择文件对话框。如图21-14所示,选择我们提供的图片文件夹(images),并在Destination中选中Copy items if needed,这样可以将文件或文件夹复制到我们的工程目录中。在Add to folders中选择Create groups,可以在Xcode中创建images组。然后在Add to targets中选择Calculator。

图 21-13 添加图片资源文件

图 21-14 添加文件或文件夹对话框
由于图片资源文件很多,下面我们通过表21-3来解释一下它们的含义。
表21-3 图片资源文件
| 文件名 | 说明 |
|---|---|
| 0.png~9.png | 0~9数字按钮默认状态显示的图片 |
| 0-down.png~9-down.png | 0~9数字按钮高亮状态显示的图片 |
| c.png | 清除按钮默认状态显示的图片 |
| c-down.png | 清除按钮高亮状态显示的图片 |
| Decimal.png | 小数点按钮默认状态显示的图片 |
| Decimal-down.png | 小数点按钮高亮状态显示的图片 |
| Plus.png | 加按钮默认状态显示的图片 |
| Plus-down.png | 加按钮高亮状态显示的图片 |
| Minus.png | 减按钮默认状态显示的图片 |
| Minus-down.png | 减按钮高亮状态显示的图片 |
| Multiply.png | 乘按钮默认状态显示的图片 |
| Multiply -down.png | 乘按钮高亮状态显示的图片 |
| Divide.png | 除按钮默认状态显示的图片 |
| Divide-down.png | 除按钮高亮状态显示的图片 |
| Equals.png | 等号按钮默认状态显示的图片 |
| Equals-down.png | 等号按钮高亮状态显示的图片 |
| icon.png | 计算器应用图标 |
| Cal.png | 主界面背景 |
21.4.2 改变设计界面大小
在开始界面设计之前,需要改变设计界面的大小。我们预计应用会在iPhone 5及之后的设备上发布,而且是竖屏,因此参考20.2节,通过图21-15所示的步骤改变设计界面大小。

图 21-15 改变设计界面大小
21.4.3 添加计算器背景
主界面中的计算器背景是一张图片,把图片放到界面中,需要将UIImageView控件添加到设计界面,具体操作可以参考20.2节。拖曳控件UIImageView到设计界面,然后选择属性检查器
,选择Image View→Image为Cal.png。
为了保证UIImageView控件大小及高宽比与背景图片Cal.png保持一致,需要修改UIImage View尺寸等属性。选中右边的尺寸检查器
,如图21-16所示的数值,设置坐标X和Y的属性,设置宽和高属性Width和Height。

图 21-16 修改UIImageView尺寸等属性
提示 原始背景图片大小是640×1136(像素),放到Retina显示屏幕中UIImageView控件大小就是320×568(像素),即高和宽减少了一半。这样设置后我们会发现设计界面下边还有空白(见图21-16),这是因为我们选择的设计界面高度是640点(1280像素),这没有关系,在iPhone 5设备上,下边多出的空白不会显示在屏幕上。
21.4.4 在设计界面中添加主标签
主界面中的主标签是用来显示输入数字和计算结果的控件,我们可以使用UILable控件。我们需要从控件库中拖曳一个Label到设计界面,并拖动它摆放到图21-17所示的位置和大小。如果你觉得拖曳不准确,可以设置它的尺寸属性,尺寸属性值X=0、Y=0、Width=320和Height=119。

图 21-17 添加Label
摆放好主标签控件的位置后,就需要设置它的文字相关属性。首先是颜色,选择主标签控件,打开属性检查器
,设置Label→Color属性为白色,如图21-18所示。再设置Label→Alignment属性为右对齐,如图21-19所示。

图 21-18 设置主标签文字颜色

图 21-19 设置主标签文字对齐
然后设置文字字体,选择Label→Font属性,如图21-20所示,在弹出的对话框中设置Font为Custom(自定义),Family为Helvetica Neue,Style为Thin,Size为50。

图 21-20 设置主标签字体
当设置完成这些属性之后,我们需要选择Label标签,拖曳Label标签轮廓填充屏幕的宽度,效果如图21-21所示。

图 21-21 效果比较
21.4.5 在设计界面中添加按钮
从原型上看,主界面有17个按钮,我们先详细介绍其中一个按钮的设计过程,其他的以此类推。左上角的按钮是7,我们先来设计按钮7。从控件库中拖曳Button控件到设计界面,如图21-22所示。

图 21-22 添加Button控件
然后我们需要设置按钮的图片,由于按钮有4种状态,分别是Default(默认)状态、Highlighted(高亮)状态、Selected(选择)状态和Disabled(不可用)状态。每种状态都对应一套按钮风格,包括颜色、背景颜色、图片、背景图片以及字体等。状态切换如图21-23所示。

图 21-23 切换Button状态
在本例中,我们只设置默认状态下Image属性为7-down.png,高亮状态下Image属性为7-down.png。如图21-24所示,选择高亮状态,然后在下面的Image属性下拉列表中选择7-down.png。

图 21-24 选择特定状态下图片
接下来还需要设置按钮的大小,打开尺寸检查器
,如图21-25所示,宽和高属性Width和Height设置为80。X和Y属性不需要在此设置。我们需要手动拖曳到左上角,具体位置参考原型设计图21-2。

图 21-25 设置按钮大小
依次按照按钮7的设计过程,设计其他16个按钮。全部设计完成后,界面如图21-26所示。

图 21-26 设计完成
为方便程序的计算,我们为主界面中的每一个按钮添加Tag属性。具体过程是选中控件,打开右边的属性检测器,选择View→Tag属性,在这里输入该控件的Tag值,Tag属性默认为0。图21-27所示是设置“0”按钮的Tag属性。按照此方法,参考表21-4,依次设置各个按钮的Tag值。

图 21-27 设置Tag属性
表21-4 按钮的Tag属性值
| 按钮 |
Tag属性值
|
|---|---|
| 0~9数字按钮 | 100~109 |
| 小数点按钮 | 0 |
| 清除按钮 | 0 |
| 等于按钮 | 0 |
| 加运算符按钮 | 200 |
| 减运算符按钮 | 201 |
| 乘运算符按钮 | 202 |
| 除运算符按钮 | 203 |
21.4.6 控件的输出口和动作
为了将访问控件状态、事件和控件联系到一起,我们引入了输出口和动作的概念。
- 输出口
为了能够访问标签等控件,我们需要给标签定义并连接输出口。单击左上角第一组按钮中的“打开辅助编辑器”按钮
,打开如图21-28所示的界面。

图 21-28 辅助编辑器
选中标签,同时按住control键,将标签主标签拖曳到图21-29所示的位置。

图 21-29 拖曳标签Label
释放鼠标,会弹出一个对话框。在Connection栏中选择Outlet,将输出口命名为mainLabel,如图21-30所示。

图 21-30 设置输出口
单击“Connect”按钮,右边的编辑界面将自动添加如下代码:
@IBOutlet var mainLabel: UILabel!
mainLabel被声明为@IBOutlet,这样就为主标签控件定义了输出口变量mainLabel,就可以在程序中访问mainLabel了,mainLabel就是主标签控件的实例。
- 动作
为了响应按钮的事件,要把按钮事件与视图控制器中的方法管理起来。为此,需要将响应事件的方法声明为@IBAction。此处列举一个动作的代码:
@IBAction func numberButtonPressed(sender: AnyObject) {}
参数sender是事件源,也就是发生动作事件的控件,AnyObject是它的类型。
添加动作与输出口类似,打开辅助编辑器界面。选中按钮控件同时按住control键,将按钮控件拖曳到图21-31所示的位置。

图 21-31 拖曳按钮控件
释放鼠标,会弹出一个如图21-32所示的对话框,在Connection栏中选择Action,Name中输入“numberButtonPressed”,其他选项用默认值就可以。

图 21-32 定义动作
单击“Connect”按钮,右边的编辑界面将自动添加如下一行代码:
@IBAction func numberButtonPressed(sender: AnyObject) {}
如果希望多个按钮共用一个方法,可以在拖曳第二个控件时候,直接把它拖曳到辅助编辑器的动作方法上。如图21-33所示,选中按钮控件,同时按住control键,将按钮控件拖曳到辅助编辑器的动作方法上,然后释放鼠标键,这样就可以为多个控件的动作定义一个方法了。类似输出口可以有多个控件对应一个输出口属性,设置方法与动作类似。

图 21-33 拖曳其他控件到动作方法
按照上面的方法依次为其他16个按钮添加动作,事件触发的方法请参考表21-5,其他的按钮设计这里不再赘述。
表21-5 按钮动作方法
| 按钮 | 触发的方法 |
|---|---|
| 0~9数字按钮 |
numberButtonPressed
|
| 小数点按钮 |
decimalPressed
|
| 清除按钮 |
clearPressed
|
| 等于按钮 |
equalsPressed
|
| 运算符按钮 |
operandPressed
|
21.4.7 视图控制器
下面我们看看视图控制器ViewController.swift的代码,代码如下:
class ViewController: UIViewController {@IBOutlet var mainLabel: UILabel!var logic : CalcLogic! ①override func viewDidLoad() { ②super.viewDidLoad()mainLabel.text = "0"logic = CalcLogic()}override func didReceiveMemoryWarning() { ③super.didReceiveMemoryWarning()logic = nil}@IBAction func operandPressed(sender: AnyObject) { ④var btn : UIButton = sender as UIButton ⑤mainLabel.text = logic.calculateByTag(btn.tag, withMainLabelString: mainLabel.text) ⑥}@IBAction func equalsPressed(sender: AnyObject) {var btn : UIButton = sender as UIButtonmainLabel.text = logic.calculateByTag(btn.tag, withMainLabelString: mainLabel.text)}@IBAction func clearPressed(sender: AnyObject) {mainLabel.text = "0"logic.clear()}@IBAction func decimalPressed(sender: AnyObject) {if logic.doesStringContainDecimal(mainLabel.text) == false { ⑦let string = mainLabel.text + "."mainLabel.text = string}}@IBAction func numberButtonPressed(sender: AnyObject) {var btn : UIButton = sender as UIButtonmainLabel.text = logic.updateMainLabelStringByNumberTag(btn.tag,withMainLabelString: mainLabel.text!) ⑧}}
上述代码第①行是声明CalcLogic可变类型变量logic。第②行代码重写UIViewController父类的viewDidLoad()方法。该方法在视图控制器加载时调用,我们在该方法中可以进行一些初始化。类似地,第③行的didReceiveMemoryWarning()方法将在视图控制器卸载或内存报警时调用,我们在该方法中应该释放一些资源。
第④行代码operandPressed方法是在用户点击运算符按钮时调用,第⑤行代码var btn: UIButton = sender as UIButton是将参数sender转换为UIButton类型。转换为UIButton类型后,才能通过访问UIButton的属性和方法,例如tag属性。第⑥行代码是调用业务逻辑层的calculateByTag方法进行计算,返回结果用来更新mainLabel内容。
第⑦行代码在用户点击小数点时调用,在该方法中判断mainLabel标签中是否已经有小数点,如果没有则在mainLabel后面拼接一个小数点。
第⑧行代码是在用户点击了数字按钮时调用的语句,通过调用业务逻辑层的updateMainLabelStringByNumberTag方法,将更新之后的字符串重新设置到控件mainLabel内容里。
