原文:macOS Controls Tutorial: Part 1/2
作者:Ernesto García
译者:kmyhy
更新说明:本教程由 Ernesto García 升级为 Xcode 8.2 / Swift 3 。上一版本由 Michael Briscoe 升级为 Xcode 6.3 / Swift 1.2 。原文作者是 Ernesto García。
如果你是一个 iOS 程序员,你想学习 Mac 开发,你有福了——由于你具备的 iOS 技能,你可以发现这很好学习!
有大量的 Cocoa 类和设计模式,比如字符串、字典和委托在 Mac 开发中都能够找到等价物。你感觉就像是回家。
但是,最大的不同在于它拥有不同的控件。 UIButton 和 UITextField 不见了——取而代之的是类似的东东(有细微不同)。
本教程介绍最常见的 macOS UI 控件——大部分 Mac app 都是由它们构成的。你会学习使用这些控件,以及它们的方法和属性,为了快速成为一个合格的开发者,你需要掌握它们!
在本文中,我们会编写一个类似于流行游戏 Mad Libs(疯狂填词) 的简单 Mac app。Mad Libs 是一个填词游戏,你可以在一段文字中插入不同的单词,并组装成一个故事——结果会非常搞笑!
当你完成 2 部分的教程时,你会基本熟练应用
- Labels 和 Text Fields
- Combo Boxes
- Popup Buttons
- Text Views
- Sliders
- Date Pickers
- Buttons
- Radio Buttons
- Check Buttons
- Image Views
注意:学习本教程需要具备基本的 macOS 开发知识。如果你是第一次接触 macOS 开发,你可以先学习我们的 macOS 开发教程初学者系列。
学习一门新平台开发技术的最好方法,是立即开始——因此不再啰嗦,让我们立即开始:]
开始
打开 Xcode,选择 File/New/Project。在项目模板对话框,选择 macOS/Application/Cocoa,这个模板让你创建一个运行在 macOS 上的图形界面 app。然后点击 Next。
https://koenig-media.raywenderlich.com/uploads/2016/12/macos-template.png’ width=’600’/>接下来,在 Product name 一栏输入 MadLibs,在 Organization name 和 Organization identifier 中填入必要内容。确保 Use Storyboards 被勾选,Language 选择 Swift。
https://koenig-media.raywenderlich.com/uploads/2016/12/macos-projectname.png’ width=’600’/>点击 Next,指定文件保存位置。点击 Create。
打开 Main.storyboard。Xcode 已经在这里为你创建了基本的 Mac app 框架:一个 Window 控制器和一个 View Controller。
选中 Window Controller 场景中的 window 对象,打开属性面板。将窗口 title 修改为 MadLibs。
https://koenig-media.raywenderlich.com/uploads/2017/01/MadLibsWindowTitle.png’ width=’600’/>一个 Mac app 通常有一个大小可变的 window,它的内容必须适应 window 的大小。要实现这样,最好的工具就是自动布局。而要在所有控件上添加自动布局将严重分散你的注意力,因此本教程我们将主要精力集中在 macOS 控件的使用上。
因此,我们只使用默认的 autoresizing 属性,这样所有的控件将保持一个固定的位置和大小,无论用户怎样修改 window 的大小——这样会导致部分控件部分超出窗口的可视区域。
注意: 如果你想了解 Auto Layout 以及在 Mac app 中如何使用自动布局,你可以参考我们的 macOS 开发教程初学者系列,第3集。
在本教程中,你需要在这个视图上添加几个 macOS 控件,视图的默认高度可能不足以放下它们。当你需要修改它的大小时,可以将 content 视图的下端往下拖,或者在 Size 检视器中修改视图的 Height 属性。
https://koenig-media.raywenderlich.com/uploads/2017/01/drag-resize-1-650x393.png’ width=’600’/>编译运行。
https://koenig-media.raywenderlich.com/uploads/2017/01/empty-window.png’ widht=’400’/>你编写了一个能够运行的 app——甚至没有编写一行代码。现在窗口中是空的,但你将用一些 mac 控件放在上面,这样它看起来会好一些!
现在基本架子就已经搭好了,你可以将主要精力转移到本教程的注意内容上来了——为 app 添加控件。
本教程剩下的步骤都将集中到单个的、不同的控件身上。你会学习每种控件的基本用法,以及如何在 MadLibs 中进行实际的运用。
NSControl——MacOS 控件的基石
NSControl 是其它 macOS 控件的基础。NSControl 提供了 UI 元素的 3 个基础功能:绘制屏幕,响应用户事件、发送 action 消息。
NSControl 是一个抽象类,你不可能直接使用它,你必须创建自己的控件子类。所有常用控件都是 NSControl 的子类,因此都继承了它的属性和方法。
一个控件的最常用的方法是读取/设置它的值,以及启用/禁用控件。这些方法分别是:
设置控件值
如果需要显示数据,通常需要改变控件的值。根据需求的不同,控件值可能是字符串、数字或者对象。大部分情况下,我们会使用和要显示的内容相匹配的值类型,不过 NSControl 也允许你设置多个不同的类型!
控件值的这些 get/set 方法是:
// getting & setting a string
let myString = myControl.stringValue
myControl.stringValue = myString
// getting & setting an integer
let myInteger = myControl.integerValue
myControl.integerValue = myInteger
// getting & setting a float
let myFloat = myControl.floatValue
myControl.floatValue = myFloat
// getting & setting a double
let myDouble = myControl.doubleValue
myControl.doubleValue = myDouble
// getting & setting an object
let myObject: Any? = myControl.objectValue
myControl.objectValue = myObject
这些 setter/getter 方法是符合 Swift 类型安全特性的。
启用/禁用控件
根据 app 状态的变化启用/禁用控件是很常见的 UI 特性。当控件被禁用,它就无法响应鼠标或键盘事件,同时会改变它的 UI 图像以表示控件被禁用,比如控件会“变灰”。
启用/禁用控件的方法分别是:
// 禁用控件
myControl.isEnabled = false
// 启用控件
myControl.isEnabled = true
// 获取控件的禁用/启用状态
let isEnabled = myControl.isEnabled
是的,就是这么简单——重要的一点是,这些方法对所有 macOS 控件来说都是一样的。在你的 UI 中用到的所有控件都是以同样的方式运作。
是时候来看一下几种常见控件了。
梦幻成真(注*:电影名) – NSTextField
文本 field 是最常见的 UI 控件之一,用于显示或编辑一段文本。在 macOS 这个控件就是 NSTextField。
NSTextField 可以显示、编辑文本。你会看到它和 iOS 中的是不同的,UILabel 显示静态文本,UITextField 用于编辑文本。在 macOS 中,这两者被合二为一了,它会根据 isEditable 属性值的不同而改变不同的行为。
如果你想把它当成 label 用,只需要将 isEditable 属性设置为 false。如果想让它作为文本输入控件——设置 isEditable 为 true。这个属性可以通过代码来改变,也可以在 IB 中设置。
为了节省你的时间,IB 会提供几个预先配置过的 macOS 控件,这些控件可以用来显示文本、编辑文本,但其实都属于 NSTextField。这些控件放在了 Object Library 中,分别是:
https://koenig-media.raywenderlich.com/uploads/2016/12/textfields-catalog.png’ width=’200’/>学习完基本的 NSTextField 理论知识之后,我们将在 MadLibs app 中使用它们!
活在过去——一个动词的过去式
我们会在 MadLibs app 中添加各种控件,它们允许你不断构建出一个搞笑的句子。当你完成后,所有不同的部分会组合起来并显示,以获得一种喜剧的效果。你的创意越丰富,结果就会越搞笑!
第一个添加的控件是文本输入框,你用它来输入一个动词,这个词会组成句子的一部分,同时还需要一个 label,提示文本输入框的作用。
打开 Main.storyboard。在 Object Library 中 Label 控件,将它拖到 View Controller 场景的 view 中。双击 label,修改它的默认文本为 Past Tense Verb(过去时态的动词):。
然后,拖一个 Text Field 控件到 view 中,把它放在 label 的右边:
https://koenig-media.raywenderlich.com/uploads/2017/01/drag-label.png’ width= ‘700’/>现在,需要为 text field 在 View Controller 中创建一个 IBOutlet。确认打开 Main.storyboard,点击 Assitant editor。确认选择 ViewController.swift 源文件,用 ctrl+左键,从故事板中的 text field 拖一条线到 ViewController.swift 中的类定义下面,松开鼠标,就会创建一个新属性:
https://koenig-media.raywenderlich.com/uploads/2016/12/textoutlet-1.png’ width=’700’/>这会弹出一个新对话框,将 IBOutlet 的 name 设置为 pastTenseVerbTextField,然后点击 Connect。
https://koenig-media.raywenderlich.com/uploads/2016/12/textoutlet-popup.png’ width=’300’/>就这么简单!在你的 View Controller 中你添加了一个 NSTextField 属性,而这个属性和主窗口中的 text field 连接在一起。
当 app 启动时,最好显示一些默认文本,这样人们才知道需要在 text field 输入些什么。因为人们都喜欢实物,而且实物和 MadLibs 总是最容易产生搞笑的效果,我们在这里不妨将 ate 作为默认的文本。
这个工作需要在 viewDidLoad() 中进行。现在,简单地设置控件的 stringValue 属性。
打开 ViewController.swift 在 viewDidLoad() 方法最后一句加上:
// 设置 pastTenseVerbTextField 的默认文本
pastTenseVerbTextField.stringValue = "ate"
编译运行。
https://koenig-media.raywenderlich.com/uploads/2017/01/buildrun-textfield.png’ width=’600’/>好了,看到输入框以及默认的文字了吗?但是如果我们想提供一个列表供用户选择该怎么办?
这就该下拉组合框出场了!
组合框 – NSComboBox
组合框很有意思——也很有用——因为它允许你从一个选项列表中选择一个值,同时还能够输入自己的文字。
它就像是一个文本框,用户可以在里面进行输入,但同时包含了一个按钮,允许显示一个列表供用户选择。在 macOS 的日期时间偏好设置面板中,你可以找到一个现成的例子:
https://koenig-media.raywenderlich.com/uploads/2016/12/date-sshot.png’ width= ‘600’/>其中,用户既可以从预定义的列表中进行选择,也可以输入自己的服务器名称。
在 macOS 中,这个控件就是 NSComboBox。
NSComboBox 有两个不同的组成部分:文本输入框用于输入字符,选项列表用于当内嵌按钮被点击时显示选项列表。这两部分的数据都可以单独进行控制。
要读取或设置 text field 的值,可以使用前面介绍的 stringValue 属性。这样,就让事情保持简单一致了,点个赞!
为列表提供选项稍微麻烦一点,但也还好了。你可以直接调用控件的方法添加单个的元素,这就和操作可变数组的方式差不多,还可以使用数据源——只要有过 iOS 编程经验和用过 UITableViewDataSource 的人都不陌生!
注意:如果你不熟悉 Data Source 的概念,你可以参考苹果的Delegate 和 Data Source 文档。
方法 1 —— 直接调用控件的方法
NSComboBox 包含了一个内部列表,暴露了几个操作这个列表的方法,比如:
// 向列表中添加对象
myComboBox.addItem(withObjectValue: anObject)
// 向列表中添加数组
myComboBox.addItems(withObjectValues: [objectOne,objectTwo,objectThree])
// 删除列表中所有对象
myComboBox.removeAllItems()
// 根据索引删除列表中某个对象
myComboBox.removeItem(at: 2)
// 得到当前所选对象在列表中的索引
let selectedIndex = myComboBox.indexOfSelectedItem
// 选定指定位置的对象
myComboBox.selectItem(at: 1)
非常简单吧?但如果你不想在 app 中以硬编码的方式指定这些选项——比如你需要一个动态的列表,列表中的数据保存在 app 之外呢?这个时候用数据源会更加方便 :]
方法 2 ——使用 Data Source
使用数据源方式组合框会在需要显示选项时查询数据源,包括一些元数据——比如列表要显示的对象的数目。要获得这些信息,我们必须在我们的类中(通常是 View Controller,也就是控件所在的控制器)实现 NSComboBoxDataSource 协议。要让组合框使用数据源,需要分两步进行。
首先,将控件的 usesDataSource 属性设置为 true。然后设置控件的 dataSource 属性,将一个实现指定协议的对象赋给这个属性。如果实现数据源的类就是包含了控件的 View Controller,则这个步骤通常会在 viewDidLoad() 方法中进行,比如这样:
class ViewController: NSViewController,NSComboBoxDataSource {
..... override func viewDidLoad() { super.viewDidLoad() myComboBox.usesDataSource = true myComboBox.dataSource = self } .....
}
注意:上述代码中,语句书写的顺序是重点。如果在设置 dataSource 属性时 useDataSource 为 false(这是默认值),则会导致数据源设置失败,你的数据源是无效的。
要实现这个协议,我们需要实现这两个数据源方法:
// 返回数据源所管理的组合框中的对象个数
func numberOfItems(in comboBox: NSComboBox) -> Int {
// anArray 是一个数组,包含了多个对象
return anArray.count
}
// 返回和组合框 index 所对应的对象
func comboBox(_ comboBox: NSComboBox,objectValueForItemAt index: Int) -> Any? {
return anArray[index]
}
最后,当数据源发生改变时,需要刷新控件,你可以调用组合框的 reloadData() 方法。
到底用哪一种方法?
如果你的选项比较少,而且你不需要经常改变它们,可以使用将选项一次性添加到内部列表的方法。如果你的选项比较大或者它们是可变的,则使用数据源方法更高效快捷。对于本教程,我们将使用方法一。
现在,你已经学习了组合框的基本用法,是时候来在我们的 app 中使用它!:]
单身酒吧——一个单数名词
在这一节,我们会用一个组合框来输入一个单数名词。你可以从列表中选择,也可以自己输入。
首先,用一个 label 来描述这个组合框的用途。
打开 Main.storyboard。从 Object Library 中找到 Label 控件,将它拖到内容视图。将它的对齐方式设为 Right ,title 设为 Singular Noun:。
注意:更快捷的做法是,按下 Option 键,拖动一个现成的 label 就能复制出另一个 label。这很方便,因为我们可以让复制出来的 label 保持相同的大小和属性。
拖一个 Combo Box 控件到内容视图。把它放在 label 的右边。
https://koenig-media.raywenderlich.com/uploads/2017/01/addcombo.png’ width=’700’/>现在为 NSComboBox 添加一个到 View Controller 的 IBOutlet。这和我们在 text field 上所用的技术是一样的:打开 Assitant Editor(确保打开的源文件窗口是 ViewController.swift),然后 ctrl+左键,从组合框拖一条线到 ViewController 类的 NSTextField 属性下边:
https://koenig-media.raywenderlich.com/uploads/2017/01/combo-outlet.png’ width=’700’/>在弹出的对话框中,设置 IBOutlet 的 name 为 singularNounCombo。
https://koenig-media.raywenderlich.com/uploads/2016/12/combo-outlet-2.png’ width=’200’/>现在这个 NSComboBox 属性连接到了组合框控件。我们接下来要添加一些数据以便在列表中展示。
打开 ViewController.swift 在刚才的 IBOutlet 后面添加:
fileprivate let singularNouns = ["dog","muppet","ninja","pirate","dev" ]
现在,在 viewDidLoad() 最后一句加入:
// 将 singularNouns 数组添加到组合框
singularNounCombo.removeAllItems()
singularNounCombo.addItems(withObjectValues: singularNouns)
singularNounCombo.selectItem(at: singularNouns.count-1)
第一句移除列表中的默认项。第二句调用 addItems() 将 singularNouns 中的名词添加到组合框。最后一句,选择列表中的最后一项。
编译运行 app,看看你的组合框是什么样子!
https://koenig-media.raywenderlich.com/uploads/2017/01/buildrun-combo.png’ width=’300’/>好——看起来一切正常。如果你点击组合框,你可以查看和选择不同的选项。
如果你想显示选项列表,但不允许用户输入自己的值呢?往后看,有一种专门的控件用于解决这个问题。
碰!黄鼠狼跑掉了(注*:一首英文儿歌)——NSPopupButton
弹出按钮允许用户从选项列表中选择,但不允许他们输入专辑的值。在 macOS 中这个控件是 NSPopupButton。
弹出按钮在 macOS 中十分常见,你几乎在每一个 app 中都能发现它们的身影——包括你正在使用的 Xcode! 在本教程中,在我们设置所用到的许多控件属性时,都要用到弹出按钮。比如:
https://koenig-media.raywenderlich.com/uploads/2016/12/popup-example.png’ width=’400’/>填充空间——向弹出按钮添加选项
就像你想到的一样,向 NSPopupButton 中添加条目就像向 NSComboBox 中添加条目——但是 NSPopUpButton 不支持数据源方式。NSPopupButton 有一个内部选项列表,以及有几个用于操作这个列表的方法:
// 向列表中添加一个选项
myPopUpbutton.addItem(withTitle: "Pop up buttons rock")
// 向列表中添加多个选项
myPopUpbutton.addItems(withTitles: ["Item 1","Item 2","Item 3"])
// 移除列表中所有项
myPopUpbutton.removeAllItems()
// 获得当前所选项的索引
let selectedIndex = myPopUpbutton.indexOfSelectedItem
// 将当前选择设置为指定位置的选项
myPopUpbutton.selectItem(at: 1)
很简单吧?这就是 macOS 控件的美妙之处了——就操作这些控件的方式上来说,有许多地方都是相同的。
是时候在你的 app 中使用一个弹出按钮了!:]
小姑居处(注*:电影名) — 一个复数名词
现在,你可以添加一个弹出按钮到 MadLibs 中,以便用户可以选择一个复数名词来构成自己的搞笑金句。
打开 Main.storyboard,拖一个 label 在 Singular Noun 标签下方。
将对齐方式修改 Right ,标题修改为 Plural Noun:。然后,拖一个 Pop Up Button 控件到窗口中,放到 label 的右边。
内容视图变成这个样子:
https://koenig-media.raywenderlich.com/uploads/2017/01/add-popup.png’ width=’700’/>我们还需要为弹出按钮创建 IBOutlet,这个你应该很熟悉了:打开 Assitant Editor,确认打开的源文件是 ViewController.swift,用 Ctrl-左键,从弹出按钮脱一条线到 ViewController 类中,创建一个 IBOutlet:
https://koenig-media.raywenderlich.com/uploads/2017/01/drag-popup.png’ width=’700’/>在弹出的对话框中,设置 IBOutlet 的 name 为 pluralNounPopup:
https://koenig-media.raywenderlich.com/uploads/2016/12/popup-outlet-2.png’ width=’300’/>现在需要为控件准备数据!
打开 ViewController.swift ,在类实现中新增属性:
fileprivate let pluralNouns = ["tacos","rainbows","iPhones","gold coins"]
在 viewDidLoad() 方法最后一句加入:
// 将 pluralNouns 添加到弹出按钮中
pluralNounPopup.removeAllItems()
pluralNounPopup.addItems(withTitles: pluralNouns)
pluralNounPopup.selectItem(at: 0)
第一句删除已有的选项。第二句条用 addItems 将复数名词数组添加到弹出按钮。第三句选中列表中第一项。
编译运行 app,你会看到:
https://koenig-media.raywenderlich.com/uploads/2017/01/buildrun-popup.png’ width=’400’/>当 app 打开后,你会看到弹出按钮显示的是第一项 tacos,如果点击按钮,你才能够看到列表的所有选项。
好,你现在有两个让用户选择的控件了,其中一个还允许用户输入单行文本。不过如果要让用户输入多行文本时怎么办?
请继续阅读 text view!
第二个文本控件 – NSTextView
和 text field 不同,text view 通常用于显示富文本。更高级的功能甚至允许显示嵌入的图片。
这个 macOS 控件就是 NSTextView。
一个充分使用了 NSTextView 的例子是文本编辑器:
https://koenig-media.raywenderlich.com/uploads/2016/12/textedit.png’ width=’700’/>NSTextView 的功能非常强大,要介绍清楚非得要另外一个单独的教程,因此我们只介绍一部分在我们的 app 中将用到的几个基本功能。 (是不是感觉松了一口气?) :]
这是我们将会用到的几个 text view 的基本方法:
// 获取 text view 的文本
let text = myTextView.string
// 设置 text view 的文本
myTextView.string = "Text views rock too!"
// 设置 text view 的背景色
myTextView.backgroundColor = NSColor.white
// 设置 text view 的文字颜色
myTextView.textColor = NSColor.black
很简单吧——没啥大不了的。
NSTextView 内置了对 NSAttributedString 的支持。如果你将一个 attributed string 传递给 text view,这些字符串将按照正确的属性进行显示,比如字体、字号大小和文字颜色。
注意:一个 attributed 字符串是一种特殊的字符串,你可以用将其中每一段字符设置为不同属性——比如字体、它的颜色、是否粗写等等。要了解 attributed string,请参考我们的 TextKit 教程。这是一个 iOS 教程,但关于 NSAttributedString 的内容其实也适用于 Mac 开发。
The Phrase that Pays(注*:歌曲名) – 添加 Text View
万事俱备,你可以添加 text view 到 MadLibs app 中了!text view 允许用户输入多个短语,这些短语将用到最后的结果中。
打开 Main.storyboard,拖一个 label 在 Plural Noun 标签下面 (也可以像前面一样,复制一个现成的 label)。将 alignment 修改为 Right,title 修改为 Phrase:。
然后,拖一个 Text View 控件到这个 label 右边。
你的窗口看起来会是这个样子:
https://koenig-media.raywenderlich.com/uploads/2017/01/add-textview.png’ width=’700’/>如果你想将试图拖大一点,你会发现奇怪的事情发生了。当你拖动窗口大小时,text view 会跟着移动,并改变位置。
https://koenig-media.raywenderlich.com/uploads/2017/01/textview-error.png’ width=’400’/>因为默认情况下,Xcode 会自动改变 text view 的约束,当 text view 的父视图改变大小时,它的位置会随之而动。我们想让 text view 固定,就需要禁用这个特性。
从 Document Outline 视图中选择 Bordered Scroll View – Text View,打开 Size 检视器。
在 AutoResizing 栏,你会看到一个矩形框,带有 4 条红线连接到它的父试图。每一条红线代表一个自动改变大小约束。我们只需要点击右边和下边两条红线,禁用它们,让它们断开连接,变成淡红色的虚线:
https://koenig-media.raywenderlich.com/uploads/2017/01/add-autores.png’ width=’300’/>现在,你再修改 window 的大小,text view 也会被固定,并和 label 进行对齐。
接下来要创建一个 NSTextView 的 IBOutlet 到 view controller。选中 textview,打开 Assistant 编辑器,确保 ViewController.swift 被打开。 Ctrl-左键,从 text view 拖一条线到 ViewController 类的其它 IBOutlet 下面。
https://koenig-media.raywenderlich.com/uploads/2017/01/textview-drag.png’ width=’700’/>重要提示:Text view 外面有一个 scroll view 包裹。在创建 IBOutlet 之前确认你选中的是 text view 而不是 scroll view 非常重要。要选中 text view,你需要连点 text view 三次,或者从 Document Outline 视图中进行选择。
在弹出窗口中,确认 type 是 NSTextView,然后将 name 设置为 phraseTextView。
https://koenig-media.raywenderlich.com/uploads/2016/12/textview-outlet2.png’ width=’200’/>然后,在 viewDidLoad() 方法最后一句加上:
// 设置 text view 的默认文本
phraseTextView.string = "Me coding Mac Apps!!!"
编译运行 app,你会看到:
https://koenig-media.raywenderlich.com/uploads/2017/01/textview-result.png’ width=’400’/>好棒啊!Mad Libs app 已经初具雏形。
按下你的按钮——NSButton
按钮是一种 macOS 控件,当它们被点击,它们会发送一条消息给 app。
这个 macOS 控件就是 NSButton。
按钮有各种样式(你可以在 Object Library 中看到)。它们的工作方式都一样,所不同的仅仅是外观。
https://koenig-media.raywenderlich.com/uploads/2016/12/button-catalog-1.png’ width=’400’>你可以选择适合于你的 app 设计风格的不同类型的按钮——请参考 macOS 人机交互指南,它建议你根据 app 的设计体验给出一些建议和指导。
通常在使用按钮时,你只需要给它指定一个 action 并设置它的标题。但是,有时你需要禁用按钮或者改变其外观。下列方法提供了这些操作:
// 禁用按钮
myButton.isEnabled = false
// 启用按钮
myButton.isEnabled = true
// 获取/设置按钮标题
let theTitle = myButton.title
myButton.title = theTitle
// 获取/设置按钮图片
let theImage = myButton.image
myButton.image = theImage
看起来很简单——在下一节,我们将添加一个按钮到 app 中,易如反掌。
按钮的那些事——添加一颗按钮
打开 Main.storyboard。拖一颗 Push Button 到内容视图。双击按钮,将标题修改为 Go! :
https://koenig-media.raywenderlich.com/uploads/2017/01/button-add.png’ width=’600’/>这次我们不需要为按钮创建 IBOutlet。
但是,我们需要为按钮创建 IBAction。这样 app 才能够知道按钮什么时候被点击!
打开 Assistant 编辑器,用 ctlr+左键,从按钮拖一条线到 View Controller 的实现代码中。
https://koenig-media.raywenderlich.com/uploads/2017/01/button-addaction.png’ width=’700’/>在弹出窗口中,确认 connection 被设为 Action。将 action 命名为 goButtonClicked。
https://koenig-media.raywenderlich.com/uploads/2016/12/button-action-2.png’ width=’300’/>当用户点击按钮,goButtonClicked() 方法将被调用。现在我们需要在方法中写几句测试代码,以验证它能正确工作。
打开 ViewController 在 goButtonClicked() 中加入:
let pastTenseVerb = pastTenseVerbTextField.stringValue
let singularNoun = singularNounCombo.stringValue
let pluralNoun = pluralNouns[pluralNounPopup.indexOfSelectedItem]
let phrase = phraseTextView.string ?? ""
let madLibSentence = "A \(singularNoun) \(pastTenseVerb) \(pluralNoun) and said,\(phrase)!"
print("\(madLibSentence)")
这段代码读取 text field、组合框、弹出按钮和 text view 中的文本,组合成 Mad Lib 金句。
注意一下 text view,它的 string 属性实际上是一个可空类型,因此它有可能为 nil。为了避免这种情况,我们需要用一个空合并操作 ??,当 string 为空时,用 “” 来代替。
目前我们暂时这样写——编译运行 app。
https://koenig-media.raywenderlich.com/uploads/2017/01/button-buildrun.png’ width=’400’/>当你点击按钮,你会看到控制台中输出了一句短小、搞笑的话。
A dev ate tacos and said: Me coding Mac Apps!!!!
不错吧?但我们还可以让它更滑稽一点吗?
让电脑读出这句话怎么样?Steve Jobs(乔布斯)曾经表演过让 Mac 向世人问好。你可以让你的电脑也这样干……说干就干!
打开 ViewController.swift 在 ViewController 实现中添加代码:
// 1
fileprivate enum VoiceRate: Int {
case slow
case normal
case fast
var speed: Float {
switch self {
case .slow:
return 60
case .normal:
return 175;
case .fast:
return 360;
}
}
}
//2
fileprivate let synth = NSSpeechSynthesizer()
首先,我们声明了一个枚举,表示语速。然后创建了一个 NSSpeechSynthesizer 对象,用于将文本合成为语音。
然后在 ViewController 实现中添加方法:
fileprivate func readSentence(_ sentence: String,rate: VoiceRate ) {
synth.rate = rate.speed
synth.stopSpeaking()
synth.startSpeaking(sentence)
}
这个方法让 synth 对象以指定的语速念出某段文本。
让我们来调用它看看!在 goButtonClicked() 方法最后一句添加:
readSentence(madLibSentence,rate: .normal)
编译运行,点击 Go! 按钮,你会听到 Mac 大声念出你的金句。
结束
在本教程第二部分,我们将学习更多的 macOS 控件,包括 滑动条、日期选择器、单选按钮、勾选框和 image view——为了最终完成我们的 Mad Libs app,这些控件中的每一个都添加到其中。
同时,有任何问题和建议,请在下面留言!