macOS 控件教程(1)

原文: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 下面。

重要提示:Text view 外面有一个 scroll view 包裹。在创建 IBOutlet 之前确认你选中的是 text view 而不是 scroll view 非常重要。要选中 text view,你需要连点 text view 三次,或者从 Document Outline 视图中进行选择。

https://koenig-media.raywenderlich.com/uploads/2017/01/textview-drag.png’ width=’700’/>

在弹出窗口中,确认 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,这些控件中的每一个都添加到其中。

同时,有任何问题和建议,请在下面留言!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。