![ce36fcd748b5f904215f610e582b0284.png](https://i-blog.csdnimg.cn/blog_migrate/cb0b675cb476b629ef90f3cadf1d510a.jpeg)
到这里,我们才开始真正的学习macOS程序开发。
macOS程序是桌面应用程序,幸运的是这类程序我们见的用的太多,所以能让我们容易地去理解它。桌面应用程序分两个部分:即界面层和逻辑层。逻辑层又分两部分,业务逻辑层与数据逻辑层。其中逻辑层的实现,大部分可以依赖我们前面所学的Swift知识,那界面层呢?只好现在从头开始学了。
程序界面的作用,无外乎是提供了一种人机交互方式。所以界面层的实现也可以分两部分:首先是页面布局的设计,即我们所看到的;其次是功能的应用,即我们所操作的。
Xcode是一个功能强大且易于使用的编辑器。它提供了两种方式用来处理界面层:Storyboard与Swift,Storyboard能让我们做到所见即所得,同时能与Swift合用,使得开发变得很轻松。所以,大约来说,前者简单后者有效。
恭喜你,从本章开始,你可以看到具体的运行程序了。每一次程序的成功运行,是我们再一次在军事演习上的胜利,再一次人生的在进步。好吧,让辛苦留住嘴角的微笑,让努力带走额头的山川,我们开始吧。
请留意,此后章节有大量的图片,请留心你的流量,我可没有钱陪给你。还有,从这一章开始,不再区分有无经验,只概述与正文两部分,你需要查看概述确定你有无需要阅读本章内容。
〜〜〜〜〜 概述 〜〜〜〜〜
我们将使用Storyboard、Swift相互协作的方式来设计界面。Xcode编辑器会为我们提供了大量的组件,用来设计界面。也就是说,在大多数情况下,我们不需要自己来设计组件就能完成程序开发。这些组件是例如按钮,文本输入框,表格这一类的东西。每个组件只跟定位、数据、样式、事件有关,当你了解了单个组件,你就大约学会了界面设计:
- 定位,即组件在页面中的位置。可使用相对或绝对数据来确定其位置,并能为其添加约束等限制。
- 样式,即组件最终呈现的模样。有两种方式确定其样式:其一,为属性赋值;其二,通过实现委托的方法进而确定组件是如何显示数据。
- 数据,即组件需要呈现的内容。有三种方式为组件提供数据:其一,为属性赋值;其二,通过实现委托的方法来为其提供数据;其三,Cocoa数据绑定。
- 事件,即组件对事件的接收与处理。是通过实现委托方法来确定将要监听和处理某操作。
下面我们将从上述的四个方面来学习如何设计程序界面。
〜〜〜〜〜 正文 〜〜〜〜〜
一、建立一个名为“iWriter”的macOS工程。
在开始之前,我们需要建立一个macOS工程,就叫它:“iWriter”。
- 启动Xcode,在“Welcome to Xcode”页面,点击左侧第二项“Create a new Xcode project”。
- 在“Choose a template for your new project”页面,选择顶部菜单项“macOS”,选择第一栏“Application”中第一项“Cocoa App”后,点击“Next”。
- 在“Choose options for your new project”页面,“Product Name”项填入“iWriter”,“Language”项选择“Swift”,勾选其下的“Use Storyboards”,勾选最下的“Include Unit Tests”及“Include UI Tests”,然后点击“Next”。注意:Team、Organization Name、Organization Identifier跟你的苹果开发账号有关,如有需要,请参考forgot2015的苹果 iOS 开发者公司账号申请流程。
- 在跳出的文件流览框里,选择工程存放的位置后,点击“Creat”,创建完成了“iWrter”项目。
二、先了解一下Xcode界面:
有了macOS工程之后,我们还需要了解Xcode的自身的布局、各区名称及其作用。这里需要我们用一下心,因为以下章节都需用到,同时到了下一章,我们只提各区及按钮的英文名,你需要知道我们讲的是那个位置和该如何操作。如Size栏,就是Inspector Area(检查区)的Size(尺寸)栏等。
- 界面的分区及功能按钮,有图参考:
- Run or Stop(运行、停止)按钮,启动或停止当前项目程序:
- 左,点击,编译并运行当前方案。可以理解为,为当前程序运行一个实例;
- 右,点击,关闭正在运行的方案或程序,可以理解为,关闭当前程序的运行实例。
- Library(库)按钮,打开库窗口:
- 编辑区为Swift时,显示大括号图标,点击跳出代码库窗口;
- 编辑区为Storyboard时,显示方圆图标,点击显示组件库窗口。
- Editor Control(编辑区控制)按钮,切换编辑区模式:
- 左,Standard Editor(基本编辑器),为Storyboard或Swift提供单一区域;
- 中,Assistant Editor(助理编辑器),为Storyboard或Swift提供双区域,当Storyboard与Swift以左右分区显示时,方便Storyboard组件关联到Swift的ViewController中;
- 右,Version Editor(版本编辑器),为Swift提供前后两个版本的代码比较。
- Area Control(大区控制)按钮,显示或隐藏非编辑区域:
- 左,显示或隐藏Navigator Area(导航区);
- 中,显示或隐藏Debug Area(调试区);
- 右,显示或隐藏Inspectors Area(检查区)。
- Navigator Area(导航区),从左到右依次为:
- Project(项目)栏,为项目文件提供分群组导航;
- Source Control(代码管理)栏,为代码分支、标签、远程提供导航;
- Symbol(标识)栏,为代码按属性、方法提供导航;
- Find(查找)栏,为工程按字符串查找提供导航;
- Issue(问题)栏,为工程按编译、运行的问题提供导航,区分警示(黄)与错误(红);
- Test(测试)栏,为单元、界面测试提供导航;
- Debug(调试)栏,为调试时线程节点提供导航;
- Breakpoint(断点)栏,为设置的所有断点提供导航;
- Report(报告)栏,为每次编译与运行的信息提供导航。
- Editor Area(编辑区),有Storyboard、Swift、Form等等编辑方式:
- 上,面包屑(文件链)栏,可快速切换各级文件;
- 下,操作区,有Storyboard、Swift、Form编辑方式。
- Inspector Area(检查区),后六项在Storyboard中选择组件后激活,从左到右依次为:
- File(文件)栏,当前文件信息,可设置;
- Help(帮助)栏,为所选类提供帮助文档;
- Identity(身份)栏,组件身份,在组件关联后,可使用;
- Attribute(属性)栏,当前组件或控制器属性信息,可设置。
- Size(尺寸)栏,当前组件或控制器尺寸信息,可设置。
- Connection(关联)栏,当前组件或控制器关联到代码中的属性、事件等信息,可设置。
- Binding(绑定)栏,数据Cocoa绑定。
- Effect(效果)栏,当前组件或控制器的整体效果信息,可设置。
- Debug Area(调试区),调试时显示运行中数据:
- 左,运行时,提供当前对象、属性、变量值;
- 右,运行时,输出运行错误。同时可通过po命令输出指定对象、属性、变量、方法的值。
![b5cc81bda4ebcb123fa36a9e32936505.png](https://i-blog.csdnimg.cn/blog_migrate/5df81621ae490a793655c317d7c4bc76.jpeg)
- Editor Area(编辑区)在Storyboard时,特有的区域、按钮说明:
- Ducoment Outline(文档大纲),可查看编辑区视图层级结构;
- MacOS Appearance(MacOS 模式),应用在MacOS模式下,浅色模式与深色模式的显示效果;
- Layout(定位)按钮及其它,从左到右:
- Update Frames(更新框架),用于修正自动布局中黄色警告;
- Embed In(嵌入),将组件嵌入到跳出窗口中选择的视图中;
- Align(对齐),对齐多个组件或视图;
- Add New Constraints(约束),四边约束、长宽约束、等宽等高约束、等宽高比约束;
- Resolve Auto Layout Issues(解决自动布局问题)。
- Autoresizing(自动布局),Inspector Area(检查区)Size(尺寸)栏中的设置项,可实现约束功能。
![08ebcfb2b7b31d1d80631ade5bbae34b.png](https://i-blog.csdnimg.cn/blog_migrate/efcc1e16209b2bef3004f484c6a680e7.jpeg)
三、开始为View Controller添加组件,数据方式为:属性赋值。
在设计界面时,如对组件不熟悉,建议使用Storyboard进行设计,然后以Outlet属性关联到View Controller中。
- 我们将在Storyboard里,添加一个Button(按钮)。记住,所有组件的添加到Storyboard的方式均与之相同,后面不再重复。
- 点击Navigator Area(导航区)的Project(项目)栏。
- 在iWriter项目下iWriter群组里,找到Main.storyboard项。点击它,确定Editor Area(编辑区)切换到Storyboard。
- Library(库)按钮此时显示方圆图标,点击Library(库)按钮,跳出库窗口。
- 库窗口上方有搜索框,可搜索。右上角有显示模式的按钮,点击可以切换组件的显示方式。点击切换到图文显示方式,这样我们可以看到各组件的样式及其相关说明。
- 选择Push Button组件,并将其拖到最下一个视图控制器。拖到视图控制器时,移动并留意出现的参考线,选择其居中后放置。
![2124f898374e9e75ed7157e375c93367.png](https://i-blog.csdnimg.cn/blog_migrate/88134932b34d58bf7c5d4f36cc575cdd.jpeg)
![8905e27d48107dcf371dd7f809690823.png](https://i-blog.csdnimg.cn/blog_migrate/39ca67ba6254da45a120aa55cab434cd.jpeg)
定位。
- 在Storyboard的ViewController里,选择组件Push Button;
- 在Storyboard的Layout(定位)里,点击Align(对齐)按钮,跳出对齐窗口。勾选水平、垂直约束,并设置约束值均为0,确认添加两个约束。表示Push Button组件将在ViewController里,水平居中和垂直居中;
- 打开Inspector Area(检查区)中Size(尺寸)栏,我们可以看见新添加两个约束。点击其右边“Edit”可重新编辑其约束值。
![51742743cb012e6917bf7b4ce13acce0.png](https://i-blog.csdnimg.cn/blog_migrate/34097ce6f08da665149cb4be2297926d.jpeg)
![98f2e2d517fba2749ce987e8c0f8e4d8.png](https://i-blog.csdnimg.cn/blog_migrate/8e47432f279849e4e9081b2785f50a3e.jpeg)
样式。
- 点击Inspector Area(检查区)的Attribute(属性)栏。
- 在Font项上,点击“T”图标,跳出窗口,选择其中的Size项,输入“24”后确认。
- 查看ViewController,“Button”组件的字体明显变大。
![f31a3576042874dc74831af6e1f38b59.png](https://i-blog.csdnimg.cn/blog_migrate/fd2b9d257b88f6a8c4718557e69c9d74.jpeg)
![f927b4ef9b04a27939350df0e8dad244.png](https://i-blog.csdnimg.cn/blog_migrate/ae93dbc912917f466f749738c2bfe8f0.jpeg)
数据。
- 点击Inspector Area(检查区)的Attribute(属性)栏。
- 在Title项上,输入“Click Me”后确认。
- 查看ViewController,“Button”组件的字符改为“Click Me”。
![a2af35da1fa395a8f9b0ceec880f1b65.png](https://i-blog.csdnimg.cn/blog_migrate/35e4dce3c661657d10a774679eb95a06.jpeg)
事件。
首先,将组件作为Outlet属性关联至ViewController(视图控制器)的类属性里。
- 点击Editor Control(编辑区控制)的中间按钮,切换Editor Area(编辑区)为Assistant Editor(辅助编辑器)。
- 保证左区打开Main.storyboard,右区打开ViewController.swift。可通过各区顶部的面包屑来打开。左边为iWriter->iWriter->Main.storyboard->Main.storyboard(Base),右边为Automatic->ViewController.swift。
- 在左区,按住键盘的“control”键,选择并拖移“Button”组件到右区。
- 放置右区的类的属性区域。
- 跳出关联窗口,在Connection项选择Outlet,表示作为以Outlet属性关联到代码。在Name栏输入“SingleButton”,点击Connection,完成属性关联。
- 查看ViewController.swift代码,类里有一个叫“SingleButton”的属性,并被标记为Outlet。
- 查看Inspector Area(检查区)的Connection(关联)栏,多了一条关联的信息。
![26e2271a5472009f9c9b81710ac9d8de.png](https://i-blog.csdnimg.cn/blog_migrate/81d70865047640d367d8f953d0914b6e.jpeg)
![21a68a6e25171f053f16689b3c1fad52.png](https://i-blog.csdnimg.cn/blog_migrate/bc8fb18b94fea8cf9a534158a1c58538.jpeg)
![c7c4ccd35a1df3cb48ff4d8a383ee492.png](https://i-blog.csdnimg.cn/blog_migrate/e6f418d9ba8369f50e9c68197f22f824.jpeg)
其次,将组件作为Action方法关联至ViewController(视图控制器)的类方法里。
- 方法如上,需要在第5步,跳出的关联窗口里,将Connection项选择Action,Name项输入“clickButton”,最终显示如图。
- 查看Inspector Area(检查区)的Connection(关联)栏里,多了一条关联信息。
- 然后在新加的“clickButton”方法里添加下列代码:
let
![40a4c93928f28b3b96681d2fae0733e9.png](https://i-blog.csdnimg.cn/blog_migrate/267cdeeb59fcf2ec16bf38ce9f9fd4ec.jpeg)
最后,点击Run and Stop(运行、停止)中的左按钮,编辑运行当前方案。这是我们开发的第一个程序,酷!
![fd7603044c42449be8a4632059c7813a.png](https://i-blog.csdnimg.cn/blog_migrate/e32f747df8439eba8151ddafbeb9f742.jpeg)
好了,我们需要学习删除组件。让我们来删除该按钮。先删除Inspector Area(检查区)的Connection(关联)栏里的关联项,再删除相关代码和该组件。如没有删除组件在Connection(关联)栏里的关联项,而先删除组件,会出现编译错误。
- 删除关联。点击Editor Control(编辑控制区)中Assistant Editor(助理编辑器),确定Editor Area(编辑区)左为Storyboard编辑,右为Swift编辑。在Storyboard编辑里,选择组件;在Inspector Area(检查区)打开Connection(关联)栏;关闭Action、Outlet关联项。
- 删除代码。在Swift里,删除前面有灰圈的代码块。
- 删除组件。在Storyboard里,删除该组件。
![2fb33f279f469056544bd3e99c207a4d.png](https://i-blog.csdnimg.cn/blog_migrate/ed8a8c1c7f6e59793c61449a6b61c5a2.jpeg)
三、再来一个复杂的组件,数据方式:实现委托。
- 我们为ViewController添加一个Outline View(大纲视图)组件,该步与上述相同。
定位
- 选择Outline View组件,点Editor Area右下角第四图标Constraints(约束)按钮,跳出Constraints(约束)窗口。将上下左右约束值各输入20,确认添加四条约束。表示Outline View(大纲视图)组件离ViewController四周的距离固定。
- 查看Editor Area(编辑区),发现Outline View(大纲视图)组件的尺寸与位置均发生了变化。
- 查看Inspector Area(检查区)的Size栏,发现新添加了4条约束。点击其右侧Edit,可修改约束值。
![64a0e96fa5d2aa7e880d015973f0af20.png](https://i-blog.csdnimg.cn/blog_migrate/3be3242fd1c2d71bd8263523e9d26ac7.jpeg)
![f1e3d05fe5e1c766da2c906e32e4ec07.png](https://i-blog.csdnimg.cn/blog_migrate/545ec3b284f67880b52ba3c9ed95376b.jpeg)
样式
- 在Editor Area(编辑区)里,点击左下角图标,打开Document Outline(文档大纲)栏;
- 选择View Controller Scene档中的Outline View项;
- 在Inspector Area(检查区)的Attribute(属性)栏中,可设置栏目数量、是否显示表头等。取消Table View档中的Headers项的勾选,表示Outline View(大纲视图)组件不显示表头;
- 选择Document Outline(文档大纲)栏中Table Column项;
- 在Storyboard编辑区选择Column的右边中点,拖拉控制其宽度;
- 在Inspector Area(检查区)的Size(属性)栏中输入width项的数值,可设计其宽度。
![ae6ad0899b79141a994923542aacf64a.png](https://i-blog.csdnimg.cn/blog_migrate/cf94f2164d6d21dcf16c682dbdb8ced7.jpeg)
![c8298804b6a1cd18093533332de6c927.png](https://i-blog.csdnimg.cn/blog_migrate/a3505ab36fb766b0050f263978ec514b.jpeg)
数据与事件
像我们这样的初学者一般建议通过Storyboard添加组件。为什么呢?从我们刚才为Storyboard添加的Outline View组件中可以看出,其Outline View组件被嵌入到一个Clip View中。如果想在代码添加NSOutlineView(Outline View对应的类)实例,由于没有嵌入到Clip View中,结果是无法在ViewController中显示出来的。
首先,为引用的组件添加Identifier。
- 在Editor Area(编辑区)里,选择Document Outline(文档大纲)栏的第一个Table Column项;
- 在Inspector Area(检查区)的Identity(身份)栏中,改Identifier项的值为leftColumn。
- 同理改第二个Table Column的Identifier为rightColumn,改第一个Table Cell View为leftCell,改第二为rightCell;
![fe67103ae0786424bb7d92b4b98555c5.png](https://i-blog.csdnimg.cn/blog_migrate/8da3a437f076b853c69b9aaef9183572.jpeg)
其次,将组件以Outlet属性关联到ViewController的类代码中。
- 切换Editor Area(编辑区)为Assistant(辅助)模式,左为Main.storyboard,右为ViewController.swift。选择Document Outline(文档大纲)栏的Outline View项。注意,上下级都没用,这也是所以不能直接将Storyboard里的Outline View组件拖入的原因。
- 按住键盘的“control”键,将Outline View项拖入ViewController.swift的类的属性区。并在跳出的窗口中,为Connection项选择Outlet,为name项输入outlineView。最后确定Connection。
![c3d6eaacf2e1139c20c7101e133b0382.png](https://i-blog.csdnimg.cn/blog_migrate/4f69364c7957855cb2268936149d835b.jpeg)
最后,为组件添加数据。
- 定义一个数据类型。示例中以目录类为数据类型,该设计支持无限级别。
- 基于数据类型准备数据。目录数据保存在文件中时用数组形式,数组按级别有序排列,应用时需要将其格式化为目录类的数据。
- 应用Outline View组件到ViewController中,需要实现其DataSource及Delegate两类委托。
- 实现其DataSource委托,通过查看其定义,确定需要实现其中三个方法。
- 实现其Delegate委托,通过查看其定义,确定需要实现其中一个方法。
//
好了,Build and Run(构建、运行),看看效果,点开各栏后展示如下。
![e6df5873d70f9c629b1fbb3823b88597.png](https://i-blog.csdnimg.cn/blog_migrate/3616e2ccd8d46cf1bc9d631c0794c07e.jpeg)
四、最后来个Horizontal Slider组件,数据方式:Cocoa绑定。
- 我们为ViewController添加Horizontal Slider组件,该步与上上述相同。
定位。
- 拖动组件左边,直到左边到左近边缘出现参考线即可。拖动组件右边,直到右边到右近边缘出现参考线即可。
- 在Inspector Area(检查区)的Size(尺寸)栏里,点击Autoresizing项外框四条箭关线,确认了上左右边边距,表示Horizontal Slider组件离ViewController的上左右边距固定不变。
![113e26e9365990d529539bff12624a5a.png](https://i-blog.csdnimg.cn/blog_migrate/855027e4b09754918a6f8c7a7bb7ebf7.jpeg)
数据
- Storyboard中选择Horizontal Slider组件;
- 在Inspector Area(检查区)的Bindings(绑定)栏中, Value档里Value项下勾选Bind to,使用默认值,Model Key Path项中填入score。表示将Horizontal Slider的值保存到NSUserDefaultsController(系统的用户中)。
- 在Inspector Area(检查区)的Bindings(绑定)栏中, Availability档里Enabled项下勾选Bind to,使用默认值,Model Key Path项中填入score。表示启动时Horizontal Slider将从NSUserDefaultsController(系统的用户中)获取值数据。
![a6d5ba53a186dcaf628dd02c5e17dc8e.png](https://i-blog.csdnimg.cn/blog_migrate/e10c0cf51d2761877e7aafb935afd2ab.jpeg)
Build and Run(构建、运行),尝试一下:你将发现Horizontal Slider值位置,就是你上次关闭前的值位置。
另:了解macOS界面,请访问:https://developer.apple.com/design/human-interface-guidelines/macos/overview/themes/
今天就学到这,下一章,macOS的菜单。
让我们在这里,遇见明天的自己!姜友华