macOS 控件教程(1)
更新说明:本教程由 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 部分的教程时,你会基本熟练应用
学习一门新平台开发技术的最好方法,是立即开始——因此不再啰嗦,让我们立即开始:] 开始打开 Xcode,选择 File/New/Project。在项目模板对话框,选择 macOS/Application/Cocoa,这个模板让你创建一个运行在 macOS 上的图形界面 app。然后点击 Next。
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 中,分别是:
我们会在 MadLibs app 中添加各种控件,它们允许你不断构建出一个搞笑的句子。当你完成后,所有不同的部分会组合起来并显示,以获得一种喜剧的效果。你的创意越丰富,结果就会越搞笑! 第一个添加的控件是文本输入框,你用它来输入一个动词,这个词会组成句子的一部分,同时还需要一个 label,提示文本输入框的作用。 打开 Main.storyboard。在 Object Library 中 Label 控件,将它拖到 View Controller 场景的 view 中。双击 label,修改它的默认文本为 Past Tense Verb(过去时态的动词):。 然后,拖一个 Text Field 控件到 view 中,把它放在 label 的右边:
编译运行。
组合框很有意思——也很有用——因为它允许你从一个选项列表中选择一个值,同时还能够输入自己的文字。 它就像是一个文本框,用户可以在里面进行输入,但同时包含了一个按钮,允许显示一个列表供用户选择。在 macOS 的日期时间偏好设置面板中,你可以找到一个现成的例子:
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 } .....
}
要实现这个协议,我们需要实现这两个数据源方法: // 返回数据源所管理的组合框中的对象个数
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:。
拖一个 Combo Box 控件到内容视图。把它放在 label 的右边。
现在,在 viewDidLoad() 最后一句加入: // 将 singularNouns 数组添加到组合框
singularNounCombo.removeAllItems()
singularNounCombo.addItems(withObjectValues: singularNouns)
singularNounCombo.selectItem(at: singularNouns.count-1)
第一句移除列表中的默认项。第二句调用 addItems() 将 singularNouns 中的名词添加到组合框。最后一句,选择列表中的最后一项。 编译运行 app,看看你的组合框是什么样子!
弹出按钮允许用户从选项列表中选择,但不允许他们输入专辑的值。在 macOS 中这个控件是 NSPopupButton。 弹出按钮在 macOS 中十分常见,你几乎在每一个 app 中都能发现它们的身影——包括你正在使用的 Xcode! 在本教程中,在我们设置所用到的许多控件属性时,都要用到弹出按钮。比如:
就像你想到的一样,向 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 的右边。 内容视图变成这个样子:
在 viewDidLoad() 方法最后一句加入: // 将 pluralNouns 添加到弹出按钮中
pluralNounPopup.removeAllItems()
pluralNounPopup.addItems(withTitles: pluralNouns)
pluralNounPopup.selectItem(at: 0)
第一句删除已有的选项。第二句条用 addItems 将复数名词数组添加到弹出按钮。第三句选中列表中第一项。 编译运行 app,你会看到:
和 text field 不同,text view 通常用于显示富文本。更高级的功能甚至允许显示嵌入的图片。 这个 macOS 控件就是 NSTextView。 一个充分使用了 NSTextView 的例子是文本编辑器:
很简单吧——没啥大不了的。 NSTextView 内置了对 NSAttributedString 的支持。如果你将一个 attributed string 传递给 text view,这些字符串将按照正确的属性进行显示,比如字体、字号大小和文字颜色。
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 右边。 你的窗口看起来会是这个样子:
编译运行 app,你会看到:
按钮是一种 macOS 控件,当它们被点击,它们会发送一条消息给 app。 这个 macOS 控件就是 NSButton。 按钮有各种样式(你可以在 Object Library 中看到)。它们的工作方式都一样,所不同的仅仅是外观。
看起来很简单——在下一节,我们将添加一个按钮到 app 中,易如反掌。 按钮的那些事——添加一颗按钮打开 Main.storyboard。拖一颗 Push Button 到内容视图。双击按钮,将标题修改为 Go! :
这段代码读取 text field、组合框、弹出按钮和 text view 中的文本,组合成 Mad Lib 金句。 注意一下 text view,它的 string 属性实际上是一个可空类型,因此它有可能为 nil。为了避免这种情况,我们需要用一个空合并操作 ??,当 string 为空时,用 “” 来代替。 目前我们暂时这样写——编译运行 app。
首先,我们声明了一个枚举,表示语速。然后创建了一个 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,这些控件中的每一个都添加到其中。 同时,有任何问题和建议,请在下面留言! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |