├── .github
├── PULL_REQUEST_TEMPLATE.md
└── issue_template.md
├── .gitignore
├── .wakatime-project
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── SUPPORT.md
├── _config.yml
├── en
├── LICENSE.txt
├── README.md
└── subtitles
│ ├── 1. Introduction to iOS 10, Xcode 8 and Swift 3.srt
│ ├── 10. Core Data.srt
│ ├── 11. Core Data Demo.srt
│ ├── 12. Autolayout.srt
│ ├── 13. Timer and Animation.srt
│ ├── 14. Dynamic Animation Demo.srt
│ ├── 15. More Segues.srt
│ ├── 16. Alerts and Action Sheets, Notifications, Application Lifecycle, and Persistence.srt
│ ├── 17. Accessibility.srt
│ ├── 2. MVC; iOS, Xcode and Swift Demonstration.srt
│ ├── 3. More Swift and the Foundation Framework.srt
│ ├── 4. Views.srt
│ ├── 5. Gestures and Multiple MVCs.srt
│ ├── 6. Multiple MVCs, View Controller Lifecycle, and Memory Management.srt
│ ├── 7. Error Handling, Extensions, Protocols, Delegation, and Scroll View.srt
│ ├── 8. Multithreading and Text Field.srt
│ └── 9. Table View.srt
├── subtitles
├── 1. Introduction to iOS 10, Xcode 8 and Swift 3.srt
├── 10. Core Data.srt
├── 11. Core Data Demo.srt
├── 12. Autolayout.srt
├── 13. Timer and Animation.srt
├── 14. Dynamic Animation Demo.srt
├── 15. More Segues.srt
├── 16. Alerts and Action Sheets, Notifications, Application Lifecycle, and Persistence.srt
├── 17. Accessibility.srt
├── 2. MVC; iOS, Xcode and Swift Demonstration.srt
├── 3. More Swift and the Foundation Framework.srt
├── 4. Views.srt
├── 5. Gestures and Multiple MVCs.srt
├── 6. Multiple MVCs, View Controller Lifecycle, and Memory Management.srt
├── 7. Error Handling, Extensions, Protocols, Delegation, and Scroll View.srt
├── 8. Multithreading and Text Field.srt
└── 9. Table View.srt
├── tools
├── download.md
├── main.swift
└── update.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ └── contents.xcworkspacedata
└── translation-style-guide.md
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 类型
2 | - [x] 翻译
3 | - [ ] 校对
4 | - [ ] 其他
5 |
6 | 集数:
7 | 开始段:
8 | 结束段:
9 |
10 | 备注(如果有,请列出):
11 | - 没有则不填
12 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 | - [ ] 请先查看 [常见问题与解答](../SUPPORT.md)
2 | - [ ] 催更请前往 [Issue #27](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/issues/27)。
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bilicookies
2 | .vscode
3 |
4 | # OS generated files #
5 | ######################
6 | .DS_Store
7 | .DS_Store?
8 | ._*
9 | .Spotlight-V100
10 | .Trashes
11 | ehthumbs.db
12 | Thumbs.db
13 | Desktop.ini
14 |
15 | # Xcode
16 | #
17 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
18 |
19 | ## Build generated
20 | build/
21 | DerivedData/
22 | Debug/
23 | Release/
24 |
25 | ## Various settings
26 | *.pbxuser
27 | !default.pbxuser
28 | *.mode1v3
29 | !default.mode1v3
30 | *.mode2v3
31 | !default.mode2v3
32 | *.perspectivev3
33 | !default.perspectivev3
34 | xcuserdata/
35 |
36 | ## Other
37 | *.moved-aside
38 | *.xcuserstate
39 |
40 | ## Obj-C/Swift specific
41 | *.hmap
42 | *.ipa
43 | *.dSYM.zip
44 | *.dSYM
45 |
46 | ## Playgrounds
47 | timeline.xctimeline
48 | playground.xcworkspace
49 |
50 | # Swift Package Manager
51 | #
52 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
53 | # Packages/
54 | .build/
55 |
56 | # CocoaPods
57 | #
58 | # We recommend against adding the Pods directory to your .gitignore. However
59 | # you should judge for yourself, the pros and cons are mentioned at:
60 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
61 | #
62 | # Pods/
63 |
64 | # Carthage
65 | #
66 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
67 | # Carthage/Checkouts
68 |
69 | Carthage/Build
70 |
71 | # fastlane
72 | #
73 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
74 | # screenshots whenever they are needed.
75 | # For more information about the recommended setup visit:
76 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
77 |
78 | fastlane/report.xml
79 | fastlane/Preview.html
80 | fastlane/screenshots
81 | fastlane/test_output
82 |
--------------------------------------------------------------------------------
/.wakatime-project:
--------------------------------------------------------------------------------
1 | Developing-iOS-10-Apps-with-Swift
2 |
3 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Each line is a file pattern followed by one or more owners.
2 |
3 | # These owners will be the default owners for everything in the repo.
4 | * @ApolloZhu @LiulietLee
5 |
6 | # Order is important; the last matching pattern takes the most precedence.
7 | *.srt @ApolloZhu
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # 任务相关说明
2 |
3 | 欢迎加入翻译的队伍!去年的现在还没有翻译完,为了避免这样的情况再次发生,希望能有更多的小伙伴们加入。Swifters of China, unite!
4 |
5 | 总之大家先 Watch + Star 这个 repository,有兴趣也可以加 QQ 群 277542197。
6 |
7 | ## 领取任务
8 |
9 | 1. 每节新内容发布以后,[issue 区](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/issues) 会开一个当节的「任务分配」issue。
10 | 2. 请到每节的 issue 中评论「翻译」或「校对」。评论的内容包括:
11 | 1. 段数。建议选择 issue 下第一条里公布的,一般会是 300 或 500 段,也可以自定义,不过为了方便管理,要求每次至少 100 段。
12 | 2. 预计完成时间。我个人的翻译速度是每小时 50 段,请结合个人情况进行估计,建议控制在一个星期以内。海外党请用本地时,并注明时区。
13 | 3. 我会结合字幕和您的需求等综合考虑后在 issue 中 @你 通知实际翻译的段数。
14 | 4. 请尽快在 issue 下回复 或 发邮件 public-apollonian@outlook.com 或 QQ 群确认。
15 | 5. 之后我会在 [看板](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/projects/1) 和 issue 顶部添加关于您任务的信息。
16 |
17 | **翻译、校对任务的段数不是指字幕文件中行数,而是指**
18 |
19 | 67 <----此处的数字
20 | 00:03:04,860 --> 00:03:06,960
21 | we talked about the NSNumber format and all that.
22 |
23 | ## 进行翻译
24 |
25 | 1. 请认真阅读并遵守 [翻译标准/校对规则](./translation-style-guide.md)。
26 | 2. 为了避免其他人也翻译同样的内容,请只翻译分配的段数。如果您不小心翻译了其他部分,请立刻告诉我,避免重复劳动。
27 | 3. 如果忙碌或者有困难一定要及时提出来,我也可以把任务转给其他人。这并不会对您有任何影响,觉得难为情可以邮件/私信我。
28 | 4. Fork 本项目到您的账户下,然后 Clone 保存到本地。
29 | 5. 如果已经 fork 过了,请通过 sync/update from master/fetch origin 等方式完成同步。
30 | 6. 翻译过程中请不要 update from master。
31 | 7. 翻译 **subtitles** 文件夹下对应 srt 文件的对应段,在英文行下面添加中文翻译。
32 | - srt 就是普通的文本文件,所以使用的程序只要能够保证保存为同样格式就行,个人偏好是 Visual Studio Code,也可以直接在 GitHub 上编辑。
33 | - 千万 **不要** 翻译 en/subtitles 文件夹里的,那些是保留原版字幕以备后用。区别方法如下:
34 | - 要翻译的文件所有的英文都只有一行;
35 | - 要翻译的文件至少第一句和最后一句都已经翻译过了。
36 | 8. 建议每完成一部分就 **commit** 一次,这样我们能对进度有个大概的把握。
37 | 9. 翻译或校对的过程中有拿不准的地方,请先尝试按照标准里提到的方法解决,也可以进入该节的 issue 中讨论(如这个词该不该翻译,该翻译成什么等)。
38 |
39 | ## 提交翻译
40 |
41 | 1. **全部** 翻译完之后提交 pull request,你会看到它出现在 [这里](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/pulls),具体步骤可以参考 [教程](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)。
42 | 2. 如果有,请在提交信息中注明我们需要特别注意的地方,和其他任务行之外的改动。
43 | 2. 我们会进行简单的校对。多半您在主项目的 pull request 下会被拒绝合并,request changes,这是正常的现象。
44 | 3. 请 merge 您 fork 下的 pull request,建议然后再简单地确认一下。
45 | 4. merge 并修改(如果有)时,主项目的 pull request 会自动更新。请评论表示可以合并到主分支。
46 | 5. 在看到主项目出现一个标题为 `集数_开始段-结束段 翻译 @你` 的 commit 之后就算完成了。如果有需要,这个时候就可以安全地删除 fork 和本地文件了。
47 |
48 | ----
49 |
50 | 本规则基于 [github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift/issues/3](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift/issues/3) 修订而成。
51 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | 本项目(包括字幕,代码等),以及原斯坦福课程均采用 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 许可协议 进行许可。协议详见 https://creativecommons.org/licenses/by-nc-sa/3.0/us/deed.zh。
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Developing iOS 10 Apps with Swift 字幕简体中文翻译项目
2 |
3 | ## iOS 11 已出,请大家移步 [https://github.com/ApolloZhu/Developing-iOS-11-Apps-with-Swift](https://github.com/ApolloZhu/Developing-iOS-11-Apps-with-Swift)
4 |
5 |
6 |
7 | 已完成前六集翻译,点此下载(字幕在 subtitles 文件夹里),其他课程录像和资料等可以查看下载列表。但本项目在 iOS 11 翻译 完成前不再继续翻译。如有需要可以参考其他项目提供的机器翻译,比如 有道字典机翻 和 另一个机翻+粗校。本项目不对机器翻译内容负责。
8 |
9 |
10 | [English Version (Outdated)](./en/README.md)
11 |
12 | [](#backers) [](#sponsors)
13 |
14 | ### 版权说明
15 |
16 |
17 |
18 | 本项目(包括字幕,代码等),以及原斯坦福课程均采用 知识共享 署名-非商业性使用-相同方式共享 3.0 美国 许可协议 进行许可。
19 |
20 | ----
21 |
22 | 如果您感兴趣,有能力,我们欢迎您参与翻译/校对本项目。详情见 [任务相关说明](./CONTRIBUTING.md)([失效备份](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/blob/master/CONTRIBUTING.md))。
23 |
24 | 关于如何获得更新,请查看 [常见问题与解答](./SUPPORT.md) 中的字幕更新章节。
25 |
26 | 如果您想支持我们,请点击项目右上角的 Star 按钮来 Star 本项目。其他如分享和打赏等方式请查看 [常见问题与解答](./SUPPORT.md) 中的支持我们章节。
27 |
28 | ### 下载
29 |
30 | (从 iTunes U 提取),其中点击 `中英字幕` 就可以下载已经翻译好了的字幕。另一个方案是 [下载整个项目](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/archive/master.zip)。`subtitles` 文件夹中是中英字幕(不一定都翻译了),`en/subtitles` 文件夹中是纯英文字幕。
31 |
32 | 字幕的格式是 `.srt`,所以您可能需要用带外挂字幕功能的视频播放器,比如 [VLC](http://www.videolan.org/vlc/index.zh.html) 或 [IINA](https://lhc70000.github.io/iina/zh-cn/) 等才可使用。其他字幕使用问题的解答请查看 [常见问题与解答](./SUPPORT.md) 的字幕使用章节。
33 |
34 | 如果您有任何建议或意见,或是在观看视频时发现了翻译有误的地方,请通过 [常见问题与解答](./SUPPORT.md) 中提供的联系方式反馈。
35 |
36 | #### 课程相关资源
37 |
38 | - iTunes U:[Developing iOS 10 Apps with Swift - Free Course by Stanford](https://itunes.apple.com/us/course/developing-ios-10-apps-with-swift/id1198467120)
39 | - [RSS 源](https://p1-u.itunes.apple.com/WebObjects/LZStudent.woa/ra/feed/COETAIHAJLZIQXJI)
40 | - [课程专辑封面](http://a2.mzstatic.com/us/r30/CobaltPublic122/v4/6b/66/d0/6b66d0af-d47f-37d6-9993-9c5237401a49/d3_64_2x.png)
41 | - [首页推广图片](http://a2.mzstatic.com/us/r30/Features122/v4/79/cb/ce/79cbce27-b961-9dfb-f044-21686543edf8/flowcase_1360_520_2x.jpeg)
42 | - CS 193P 课程地址:[CS 193P iPhone Application Development](http://web.stanford.edu/class/cs193p/cgi-bin/drupal/)
43 | - Paul Hegarty:[piazza](https://piazza.com/professors/show/paul_hegarty)
44 |
45 | #### 项目相关资源
46 |
47 | - [Developing iOS 9 Apps with Swift 字幕翻译](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift)
48 | - [Developing iOS 8 Apps with Swift 字幕翻译](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift)
49 | - 提取字幕:[CCExtractor](https://www.ccextractor.org/)
50 | - 字幕重排:[X140Yu/Developing_iOS_8_Apps_With_Swift/tools/trim.rb](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift/blob/master/tools/trim.rb)
51 |
52 | ----
53 |
54 |
55 | ## Contributors
56 |
57 | This project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md).
58 |
59 |
60 |
61 | ## Backers
62 |
63 | Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Developing-iOS-10-Apps-with-Swift#backer)]
64 |
65 |
66 |
67 |
68 | ## Sponsors
69 |
70 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/Developing-iOS-10-Apps-with-Swift#sponsor)]
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
91 |
92 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 已完成前六集翻译,点此下载(字幕在 subtitles 文件夹里),其他课程录像和资料等可以查看下载列表。但本项目在 iOS 11 翻译 完成前不再继续翻译。如有需要可以参考其他项目提供的机器翻译,比如 有道字典机翻 和 另一个机翻+粗校。本项目不对机器翻译内容负责。
4 |
5 |
6 | # 常见问题与解答
7 |
8 | 如果您阅读完后还是有问题,请通过 “联系我们” 中提供的方式咨询。
9 |
10 | ## 联系我们
11 |
12 | 推荐 [GitHub Issues](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/issues/new),或者发电子邮件到 [public-apollonian@outlook.com](mailto:public-apollonian@outlook.com)。
13 |
14 | ## 字幕使用
15 |
16 | ### 字幕乱码
17 |
18 | 如果字幕有乱码,请点击 [中文乱码报错用 Issue](https://github.com/x140yu/Developing_iOS_8_Apps_With_Swift/issues/131) 进行乱码的报错和寻求解决方案。
19 |
20 | ### 字幕看不清
21 |
22 | 播放器应该都可以设置字幕样式,所以不接受在字幕中加上声明样式的代码。
23 |
24 | 设置方法每个系统每个播放器的每个版本都可能不一样,请自行搜索/研究。
25 |
26 | 推荐样式是白字+黑边,一般情况下都是能看清的。
27 |
28 | ## 字幕更新
29 |
30 | ### 如何关注更新?
31 |
32 | 如果您想收到每集翻译完成的更新,请订阅 [RSS源](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/releases.atom)。如果您想要更密切地获得最新动态,您也可以 [关注(Watch)项目的更新](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/subscription)。
33 |
34 | ## 支持我们
35 |
36 | 在此先感谢所有关注、分享和参与本项目的所有人!
37 |
38 | ### 您的分享非常重要!
39 |
40 | 除了 ***Star*** 之外,同时也希望您能够通过各种国内外社交平台,如 微信公众号,微博,博客,开发者头条,简书,CSDN 等为我们宣传推广,以**吸引更多的人加入翻译,加快翻译速度**,同时帮助更多有需要的人。
41 |
42 | ### 为什么捐助一直在拖?
43 |
44 | 十分感谢大家的好意,我们之后应该会支持微信、支付宝和其他平台的打赏。资金的用途尚未定,但一定会保持公开透明。可以理解大家的心情,先不论我们不是为了盈利,但是现在翻译还没有完成(而且还经常被催),接受大家的善意会于心有愧。
45 |
46 |
47 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/en/LICENSE.txt:
--------------------------------------------------------------------------------
1 | This work and the original work by Stanford University are both licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. The license is available at http://creativecommons.org/licenses/by-nc-sa/3.0/us/.
2 |
--------------------------------------------------------------------------------
/en/README.md:
--------------------------------------------------------------------------------
1 | # Simplified Chinese Subtitle Translation Project for Developing iOS 10 Apps with Swift
2 |
3 | [中文版本](../README.md)
4 |
5 | ***This document is outdated. Please refer to the above Chinese version for the latest information.***
6 |
7 | We have not yet finished translating. You may view our progress by
8 |
9 | - [Watching the repository](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/subscription)
10 | - [Viewing Kanban for project progress](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/projects/1)
11 |
12 | You may also support us by clicking the Star button on the upper right corner of this repository. Meanwhile, we'd like you to share this repository or website with your friends, through social media platforms, such as reddit, twitter, facebook, tumblr, etc., as well as other developer forums and websites, so we may help more people in need.
13 |
14 | If you are interested in helping us translate, please read [Translation Style Guide/Proofread Guidelines (Chinese)](../translation-style-guide.md) carefully,and refer to [Must knows about collaboration (Chinese)](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/issues/2). We reserve rights to close any pull request that doesn't follow these regulations.
15 |
16 | ### Download Subtitles
17 |
18 | Please download the [Project Zip Archive](https://github.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/archive/master.zip). You can find original subtitles in folder `en/subtitles`, and translated subtitles in folder `subtitles`.
19 |
20 | The subtitles are provided as `.srt` files, therefore, you need video players that will support loading external subtitle files, such as [VLC](http://www.videolan.org/vlc/index.html). If you are unable to decode subtitle files correctly, please search for the solutions form, and/or report new issues to [Encoding Issues (Chinese)](https://github.com/x140yu/Developing_iOS_8_Apps_With_Swift/issues/131).
21 |
22 | ### Download Videos and Other Course Materials
23 |
24 | [Download List](../tools/download.md), which is automatically generated from iTunes U, contains resources available for download from iTunes U.
25 |
26 | ### Other Course Related Resources
27 |
28 | - iTunes U:[Developing iOS 10 Apps with Swift - Free Course by Stanford](https://itunes.apple.com/us/course/developing-ios-10-apps-with-swift/id1198467120)
29 | - [RSS Feed](https://p1-u.itunes.apple.com/WebObjects/LZStudent.woa/ra/feed/COETAIHAJLZIQXJI)
30 | - [Album Cover](http://a2.mzstatic.com/us/r30/CobaltPublic122/v4/6b/66/d0/6b66d0af-d47f-37d6-9993-9c5237401a49/d3_64_2x.png)
31 | - [Showcase Image](http://a2.mzstatic.com/us/r30/Features122/v4/79/cb/ce/79cbce27-b961-9dfb-f044-21686543edf8/flowcase_1360_520_2x.jpeg)
32 | - CS 193P on Stanford website:[CS 193P iPhone Application Development](http://web.stanford.edu/class/cs193p/cgi-bin/drupal/)
33 |
34 | ### Translation Related Resources
35 |
36 | - [Developing iOS 9 Apps with Swift Translation](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift)
37 | - [Developing iOS 8 Apps with Swift Translation](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift)
38 | - Tool to extract subtitles:[CCExtractor](https://www.ccextractor.org/)
39 | - Reformatting subtitles:[X140Yu/Developing_iOS_8_Apps_With_Swift/tools/trim.rb](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift/blob/master/tools/trim.rb)
40 |
41 | ----
42 |
43 | ### Copyright Information
44 |
45 |
46 |
47 | This work and the original work by Stanford University are both licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License.
48 |
49 | ----
50 |
51 |
52 |
--------------------------------------------------------------------------------
/subtitles/17. Accessibility.srt:
--------------------------------------------------------------------------------
1 | 1
2 | 00:00:00,401 --> 00:00:02,000
3 | 本字幕由志愿者义务贡献,采用许可协议
4 | 知识共享 署名-非商业性使用-相同方式共享 3.0 美国
5 |
6 | 2
7 | 00:00:02,069 --> 00:00:07,506
8 | Stanford University.
9 | 斯坦福大学
10 |
11 | 3
12 | 00:00:07,575 --> 00:00:12,410
13 | >> Okay, welcome to Stanford CS193P, Winter of 2017.
14 | 欢迎参加 2017 年冬季学期斯坦福
15 |
16 | 4
17 | 00:00:12,479 --> 00:00:15,447
18 | This is Developing iOS Applications,
19 | CS193P 课程,iOS 应用程序开发
20 |
21 | 5
22 | 00:00:15,515 --> 00:00:18,416
23 | this is lecture number 17, I said.
24 |
25 | 6
26 | 00:00:18,485 --> 00:00:21,119
27 | Yes, and we have a guest lecturer today
28 |
29 | 7
30 | 00:00:21,188 --> 00:00:24,056
31 | who's gonna talk to us about accessibility.
32 |
33 | 8
34 | 00:00:24,125 --> 00:00:25,223
35 | His name is Skylar Peterson.
36 |
37 | 9
38 | 00:00:25,292 --> 00:00:26,592
39 | Why don't you come up here, Skylar?
40 |
41 | 10
42 | 00:00:28,662 --> 00:00:29,761
43 | It's all yours.
44 |
45 | 11
46 | 00:00:29,830 --> 00:00:31,696
47 | Thank you very much.
48 |
49 | 12
50 | 00:00:31,765 --> 00:00:33,297
51 | All righty.
52 |
53 | 13
54 | 00:00:33,366 --> 00:00:34,499
55 | Good afternoon, everybody.
56 |
57 | 14
58 | 00:00:34,568 --> 00:00:36,468
59 | As he said, my name is Skylar Peterson.
60 |
61 | 15
62 | 00:00:36,536 --> 00:00:39,571
63 | I am a member of Apple's Accessibility team.
64 |
65 | 16
66 | 00:00:39,640 --> 00:00:41,373
67 | If you don't know exactly what I mean by that,
68 |
69 | 17
70 | 00:00:41,442 --> 00:00:42,174
71 | then don't worry.
72 |
73 | 18
74 | 00:00:42,243 --> 00:00:44,609
75 | It's what I'm here to talk to you about today.
76 |
77 | 19
78 | 00:00:44,678 --> 00:00:45,877
79 | I first wanna thank Paul for
80 |
81 | 20
82 | 00:00:45,946 --> 00:00:47,412
83 | inviting us here to speak today.
84 |
85 | 21
86 | 00:00:47,481 --> 00:00:50,215
87 | Hopefully you'll find what I have to say meaningful in some
88 |
89 | 22
90 | 00:00:50,284 --> 00:00:53,085
91 | way, and choose to apply it to your own work in the future.
92 |
93 | 23
94 | 00:00:54,988 --> 00:00:56,054
95 | So before we get started,
96 |
97 | 24
98 | 00:00:56,123 --> 00:00:58,089
99 | let me tell you just a little bit about myself.
100 |
101 | 25
102 | 00:00:58,158 --> 00:01:00,959
103 | I actually graduated from Stanford in 2014.
104 |
105 | 26
106 | 00:01:01,028 --> 00:01:03,195
107 | I studied computer science, and
108 |
109 | 27
110 | 00:01:03,264 --> 00:01:05,230
111 | my concentration was in HCI.
112 |
113 | 28
114 | 00:01:05,299 --> 00:01:07,165
115 | I took this class while I was here, and
116 |
117 | 29
118 | 00:01:07,234 --> 00:01:09,768
119 | it's actually one of the reasons that I fell in love
120 |
121 | 30
122 | 00:01:09,837 --> 00:01:12,737
123 | with iOS as a platform and why I'm in the job I'm in today,
124 |
125 | 31
126 | 00:01:12,806 --> 00:01:14,505
127 | so thank you for that as well.
128 |
129 | 32
130 | 00:01:14,574 --> 00:01:17,209
131 | After I graduated I spent a year and a half working at
132 |
133 | 33
134 | 00:01:17,277 --> 00:01:19,778
135 | an enterprise software company called Citrix,
136 |
137 | 34
138 | 00:01:19,846 --> 00:01:22,514
139 | where I worked on two different iOS applications.
140 |
141 | 35
142 | 00:01:22,582 --> 00:01:24,316
143 | And then a little over a year ago,
144 |
145 | 36
146 | 00:01:24,384 --> 00:01:27,085
147 | I made the jump to the Accessibility team at Apple,
148 |
149 | 37
150 | 00:01:27,154 --> 00:01:28,754
151 | where I focus mainly on iOS.
152 |
153 | 38
154 | 00:01:30,890 --> 00:01:32,123
155 | there's a couple things that I'd like to cover with you.
156 |
157 | 39
158 | 00:01:32,124 --> 00:01:33,357
159 | So for today,
160 |
161 | 40
162 | 00:01:33,427 --> 00:01:34,259
163 | First of all,
164 |
165 | 41
166 | 00:01:34,327 --> 00:01:37,529
167 | what exactly do we mean when we say accessibility?
168 |
169 | 42
170 | 00:01:37,598 --> 00:01:39,197
171 | And once you understand that,
172 |
173 | 43
174 | 00:01:39,265 --> 00:01:42,167
175 | how do you take the tools that we've created for you and
176 |
177 | 44
178 | 00:01:42,236 --> 00:01:45,303
179 | apply them to your own work to make your apps accessible?
180 |
181 | 45
182 | 00:01:45,372 --> 00:01:47,906
183 | So included in that we're gonna take a look at
184 |
185 | 46
186 | 00:01:47,975 --> 00:01:49,474
187 | the UIAccessibility API.
188 |
189 | 47
190 | 00:01:49,542 --> 00:01:52,844
191 | We're gonna take a look at several vision accommodations
192 |
193 | 48
194 | 00:01:52,913 --> 00:01:56,448
195 | that you should consider when designing your applications,
196 |
197 | 49
198 | 00:01:56,517 --> 00:01:59,184
199 | and specifically I'm going to call out dynamic
200 |
201 | 50
202 | 00:01:59,253 --> 00:02:01,019
203 | type as an important feature.
204 |
205 | 51
206 | 00:02:01,088 --> 00:02:04,189
207 | And at the end I'd like to discuss some opportunities
208 |
209 | 52
210 | 00:02:04,258 --> 00:02:07,292
211 | available to you as a developer in the accessibility
212 |
213 | 53
214 | 00:02:07,361 --> 00:02:07,793
215 | space.
216 |
217 | 54
218 | 00:02:07,861 --> 00:02:09,861
219 | So let's get started.
220 |
221 | 55
222 | 00:02:09,930 --> 00:02:14,533
223 | I'd like to begin with a brief video that
224 |
225 | 56
226 | 00:02:14,601 --> 00:02:19,737
227 | Apple produced towards the end of last year.
228 |
229 | 57
230 | 00:02:19,806 --> 00:02:23,609
231 | [MUSIC]
232 |
233 | 58
234 | 00:02:23,677 --> 00:02:26,511
235 | People think that having a disability is a barrier.
236 |
237 | 59
238 | 00:02:26,580 --> 00:02:31,950
239 | [MUSIC].
240 |
241 | 60
242 | 00:02:32,019 --> 00:02:34,186
243 | But that's not the way I see it.
244 |
245 | 61
246 | 00:02:34,254 --> 00:02:37,021
247 | It. [MUSIC]
248 |
249 | 62
250 | 00:02:37,090 --> 00:02:39,157
251 | You can catch up with friends.
252 |
253 | 63
254 | 00:02:39,226 --> 00:02:41,359
255 | [MUSIC]
256 |
257 | 64
258 | 00:02:41,428 --> 00:02:43,562
259 | Ready? You can capture a moment with
260 |
261 | 65
262 | 00:02:43,631 --> 00:02:44,463
263 | your family.
264 |
265 | 66
266 | 00:02:44,531 --> 00:02:46,865
267 | One face, small face.
268 |
269 | 67
270 | 00:02:46,933 --> 00:02:47,966
271 | Focus log.
272 |
273 | 68
274 | 00:02:48,035 --> 00:02:50,602
275 | [MUSIC]
276 |
277 | 69
278 | 00:02:50,670 --> 00:02:53,304
279 | And you can start the day bright and early.
280 |
281 | 70
282 | 00:02:53,373 --> 00:02:58,076
283 | [MUSIC]
284 |
285 | 71
286 | 00:02:58,145 --> 00:03:00,812
287 | You can take a trip to somewhere new.
288 |
289 | 72
290 | 00:03:00,881 --> 00:03:06,585
291 | [MUSIC]
292 |
293 | 73
294 | 00:03:06,653 --> 00:03:08,286
295 | 3 miles to the summit.
296 |
297 | 74
298 | 00:03:08,355 --> 00:03:09,888
299 | [MUSIC]
300 |
301 | 75
302 | 00:03:09,957 --> 00:03:13,091
303 | You can concentrate on every word of the story.
304 |
305 | 76
306 | 00:03:13,159 --> 00:03:15,560
307 | A bird begun to sing.
308 |
309 | 77
310 | 00:03:15,628 --> 00:03:17,362
311 | Jack opened his eyes.
312 |
313 | 78
314 | 00:03:17,431 --> 00:03:19,664
315 | [MUSIC]
316 |
317 | 79
318 | 00:03:19,733 --> 00:03:22,367
319 | You can take the long way home.
320 |
321 | 80
322 | 00:03:22,436 --> 00:03:32,310
323 | [MUSIC]
324 |
325 | 81
326 | 00:03:32,378 --> 00:03:33,811
327 | Or edit a film.
328 |
329 | 82
330 | 00:03:33,880 --> 00:03:35,346
331 | [MUSIC]
332 |
333 | 83
334 | 00:03:35,415 --> 00:03:36,614
335 | Like this one.
336 |
337 | 84
338 | 00:03:36,683 --> 00:03:43,688
339 | [MUSIC].
340 |
341 | 85
342 | 00:03:43,757 --> 00:03:46,457
343 | When technology is designed for everyone,
344 |
345 | 86
346 | 00:03:46,526 --> 00:03:48,326
347 | [MUSIC]
348 |
349 | 87
350 | 00:03:48,395 --> 00:03:53,398
351 | It lets anyone do what they love, including me.
352 |
353 | 88
354 | 00:03:53,467 --> 00:03:56,334
355 | [MUSIC]
356 |
357 | 89
358 | 00:03:56,403 --> 00:03:57,769
359 | So the woman narrating and
360 |
361 | 90
362 | 00:03:57,838 --> 00:04:00,705
363 | whom you saw featured throughout that video is named
364 |
365 | 91
366 | 00:04:00,773 --> 00:04:03,375
367 | Sady, and she has cerebral palsy.
368 |
369 | 92
370 | 00:04:03,444 --> 00:04:06,578
371 | And she's the principal editor on that video,
372 |
373 | 93
374 | 00:04:06,646 --> 00:04:09,481
375 | which I think is a powerful example of the way in which
376 |
377 | 94
378 | 00:04:09,549 --> 00:04:12,483
379 | technology can empower people with disabilities and
380 |
381 | 95
382 | 00:04:12,552 --> 00:04:14,586
383 | fundamentally change their lives.
384 |
385 | 96
386 | 00:04:14,654 --> 00:04:16,955
387 | So that is really what accessibility is all about.
388 |
389 | 97
390 | 00:04:17,024 --> 00:04:20,325
391 | It's making technology work for everyone,
392 |
393 | 98
394 | 00:04:20,393 --> 00:04:23,061
395 | making it accessible for everyone.
396 |
397 | 99
398 | 00:04:23,130 --> 00:04:26,131
399 | So let's take a look at some statistics.
400 |
401 | 100
402 | 00:04:26,199 --> 00:04:30,035
403 | There are 285 million people worldwide who have some sort
404 |
405 | 101
406 | 00:04:30,103 --> 00:04:33,371
407 | of low vision condition or who are entirely blind.
408 |
409 | 102
410 | 00:04:33,440 --> 00:04:38,076
411 | There are 360 million who are hard of hearing or deaf.
412 |
413 | 103
414 | 00:04:38,145 --> 00:04:42,947
415 | One in every 12 men is colorblind in some way, and 1
416 |
417 | 104
418 | 00:04:43,016 --> 00:04:48,119
419 | in 68 children fall somewhere on the autism spectrum.
420 |
421 | 105
422 | 00:04:48,187 --> 00:04:51,322
423 | And so what this means is that worldwide there are over
424 |
425 | 106
426 | 00:04:51,391 --> 00:04:54,525
427 | a billion people that have a disability of some sort.
428 |
429 | 107
430 | 00:04:54,594 --> 00:04:56,795
431 | Or in other words, one in seven.
432 |
433 | 108
434 | 00:04:56,864 --> 00:04:59,864
435 | So by no means is accessibility a small issue.
436 |
437 | 109
438 | 00:04:59,933 --> 00:05:01,733
439 | It affects a lot of people and
440 |
441 | 110
442 | 00:05:01,802 --> 00:05:05,570
443 | if your app has an audience of any significant size you're
444 |
445 | 111
446 | 00:05:05,638 --> 00:05:08,573
447 | going to have users that have disabilities.
448 |
449 | 112
450 | 00:05:08,641 --> 00:05:11,743
451 | And you should be doing the best, your best to make sure
452 |
453 | 113
454 | 00:05:11,812 --> 00:05:14,946
455 | that whatever you're working on works for everybody.
456 |
457 | 114
458 | 00:05:15,015 --> 00:05:18,449
459 | So at Apple we think of accessibility in four distinct
460 |
461 | 115
462 | 00:05:18,518 --> 00:05:21,519
463 | groups.
464 |
465 | 116
466 | 00:05:21,588 --> 00:05:24,789
467 | which includes things like autism, dyslexia, and
468 |
469 | 117
470 | 00:05:24,857 --> 00:05:27,225
471 | other forms of learning disability.
472 |
473 | 118
474 | 00:05:27,294 --> 00:05:30,395
475 | Physical and motor skills, so people that have tremors or
476 |
477 | 119
478 | 00:05:30,463 --> 00:05:33,398
479 | Parkinson's and maybe can't make precise movements
480 |
481 | 120
482 | 00:05:33,467 --> 00:05:36,001
483 | or gestures, but this also includes people who
484 |
485 | 121
486 | 00:05:36,069 --> 00:05:38,670
487 | are paralyzed or have a limited set of digits that
488 |
489 | 122
490 | 00:05:38,739 --> 00:05:40,938
491 | they can use to interact with the system.
492 |
493 | 123
494 | 00:05:41,007 --> 00:05:43,641
495 | For instance a single finger or a single toe, or
496 |
497 | 124
498 | 00:05:43,710 --> 00:05:45,477
499 | in Sadie's case, her head.
500 |
501 | 125
502 | 00:05:47,381 --> 00:05:51,049
503 | Vision, which covers a spectrum of vision impairment
504 |
505 | 126
506 | 00:05:51,118 --> 00:05:53,885
507 | from low vision to completely blind, and
508 |
509 | 127
510 | 00:05:53,953 --> 00:05:57,455
511 | also includes different forms of color blindness.
512 |
513 | 128
514 | 00:05:57,524 --> 00:05:59,056
515 | And finally we have hearing,
516 |
517 | 129
518 | 00:05:59,125 --> 00:06:02,160
519 | which also like vision exists on a spectrum from the hard of
520 |
521 | 130
522 | 00:06:02,229 --> 00:06:04,096
523 | hearing to the completely deaf.
524 |
525 | 131
526 | 00:06:05,865 --> 00:06:09,200
527 | So now our team has developed a huge set of features on iOS
528 |
529 | 132
530 | 00:06:09,268 --> 00:06:12,603
531 | that assists in all of these categories, and best of all
532 |
533 | 133
534 | 00:06:12,672 --> 00:06:16,040
535 | they all come baked into the system from the beginning.
536 |
537 | 134
538 | 00:06:16,109 --> 00:06:19,410
539 | So they're all on all of your iOS devices that you can turn
540 |
541 | 135
542 | 00:06:19,479 --> 00:06:21,112
543 | on, no add-ons required.
544 |
545 | 136
546 | 00:06:21,181 --> 00:06:23,681
547 | And as much as I'd like to go feature by feature and
548 |
549 | 137
550 | 00:06:23,750 --> 00:06:26,684
551 | tell you why each of these is cool, and why it's necessary
552 |
553 | 138
554 | 00:06:26,753 --> 00:06:29,454
555 | and solves the problem, we don't have all night, so
556 |
557 | 139
558 | 00:06:29,523 --> 00:06:31,356
559 | I'm going to focus on just a couple.
560 |
561 | 140
562 | 00:06:31,425 --> 00:06:34,759
563 | But I do encourage you to go and check them out for
564 |
565 | 141
566 | 00:06:34,828 --> 00:06:36,561
567 | You can find accessibility settings on your device by
568 |
569 | 142
570 | 00:06:36,562 --> 00:06:38,295
571 | yourself.
572 |
573 | 143
574 | 00:06:38,365 --> 00:06:39,631
575 | going to General and
576 |
577 | 144
578 | 00:06:39,699 --> 00:06:43,501
579 | tapping on Accessibility where you'll find a long list of
580 |
581 | 145
582 | 00:06:43,570 --> 00:06:47,071
583 | all the features that you can enable on your devices.
584 |
585 | 146
586 | 00:06:47,140 --> 00:06:49,340
587 | What I'd like to do now though is demo for you,
588 |
589 | 147
590 | 00:06:49,409 --> 00:06:52,343
591 | one of our most popular pieces of assistive technology which
592 |
593 | 148
594 | 00:06:52,412 --> 00:06:53,444
595 | is called VoiceOver.
596 |
597 | 149
598 | 00:06:53,513 --> 00:06:56,681
599 | It's a screen reader that allows blind and low vision
600 |
601 | 150
602 | 00:06:56,750 --> 00:07:00,351
603 | users to use a touch screen by audibly describing elements of
604 |
605 | 151
606 | 00:07:00,420 --> 00:07:02,887
607 | the screen as they pan or swipe around it.
608 |
609 | 152
610 | 00:07:02,956 --> 00:07:05,556
611 | So without a technology like this, blind users would be
612 |
613 | 153
614 | 00:07:05,625 --> 00:07:08,426
615 | unable to use the iPhone which is why it's really important
616 |
617 | 154
618 | 00:07:08,494 --> 00:07:11,062
619 | for you to take advantage of the API which I'm gonna get
620 |
621 | 155
622 | 00:07:11,130 --> 00:07:13,865
623 | into in a little bit so that your apps play well with it.
624 |
625 | 156
626 | 00:07:17,804 --> 00:07:20,371
627 | So, I have my device here on the home screen and
628 |
629 | 157
630 | 00:07:20,440 --> 00:07:22,106
631 | I'm gonna turn VoiceOver on.
632 |
633 | 158
634 | 00:07:22,175 --> 00:07:25,543
635 | And what you're gonna notice is that it's going to focus on
636 |
637 | 159
638 | 00:07:25,612 --> 00:07:27,445
639 | the first element of the screen,
640 |
641 | 160
642 | 00:07:27,514 --> 00:07:30,114
643 | which is the Mail app in the upper left corner.
644 |
645 | 161
646 | 00:07:30,183 --> 00:07:31,349
647 | VoiceOver on.
648 |
649 | 162
650 | 00:07:31,418 --> 00:07:32,083
651 | Mail.
652 |
653 | 163
654 | 00:07:32,152 --> 00:07:33,751
655 | No unread emails.
656 |
657 | 164
658 | 00:07:33,820 --> 00:07:36,520
659 | And it described it to me, and told me some extra information
660 |
661 | 165
662 | 00:07:36,589 --> 00:07:39,123
663 | about it, for instance, that I have no unread emails.
664 |
665 | 166
666 | 00:07:39,192 --> 00:07:43,160
667 | So if I wanted to navigate between items,
668 |
669 | 167
670 | 00:07:43,229 --> 00:07:47,731
671 | if I wanna go item by item, I can swipe right or left.
672 |
673 | 168
674 | 00:07:47,800 --> 00:07:50,568
675 | Calendar, photos, camera.
676 |
677 | 169
678 | 00:07:50,637 --> 00:07:53,805
679 | And it's going to read to me the description of each
680 |
681 | 170
682 | 00:07:53,874 --> 00:07:55,140
683 | But if we're on the home screen which I'm here fairly
684 |
685 | 171
686 | 00:07:55,141 --> 00:07:56,407
687 | item as I go.
688 |
689 | 172
690 | 00:07:56,476 --> 00:07:59,077
691 | frequently, I know my way around, I can also just feel
692 |
693 | 173
694 | 00:07:59,146 --> 00:08:01,145
695 | my way around the screen with my finger.
696 |
697 | 174
698 | 00:08:01,214 --> 00:08:04,415
699 | You tapped on Music.
700 |
701 | 175
702 | 00:08:04,484 --> 00:08:06,952
703 | And once I found exactly what I'm looking for,
704 |
705 | 176
706 | 00:08:07,020 --> 00:08:09,487
707 | a double tap acts like a single tap would when you
708 |
709 | 177
710 | 00:08:09,556 --> 00:08:10,955
711 | don't have VoiceOver on.
712 |
713 | 178
714 | 00:08:11,024 --> 00:08:12,023
715 | So it's gonna open Music.
716 |
717 | 179
718 | 00:08:15,795 --> 00:08:18,129
719 | Music, this is now playing screen, button.
720 |
721 | 180
722 | 00:08:18,198 --> 00:08:21,899
723 | Now because music is a first party application,
724 |
725 | 181
726 | 00:08:21,968 --> 00:08:23,134
727 | Apple engineers have gone through and
728 |
729 | 182
730 | 00:08:23,203 --> 00:08:26,237
731 | made sure that all of the UI in that app is accessible.
732 |
733 | 183
734 | 00:08:26,306 --> 00:08:29,106
735 | So VoiceOver interacts with this interface
736 |
737 | 184
738 | 00:08:29,175 --> 00:08:31,042
739 | exactly the same way that it would on the home screen,
740 |
741 | 185
742 | 00:08:31,111 --> 00:08:33,978
743 | I could swipe, [SOUND] Or
744 |
745 | 186
746 | 00:08:34,046 --> 00:08:35,580
747 | find exactly what I'm looking for.
748 |
749 | 187
750 | 00:08:37,083 --> 00:08:41,452
751 | Now VoiceOver, because it is intercepting gestures
752 |
753 | 188
754 | 00:08:41,521 --> 00:08:42,653
755 | that are normally used for
756 |
757 | 189
758 | 00:08:42,722 --> 00:08:44,956
759 | other things when VoiceOver's turned off.
760 |
761 | 190
762 | 00:08:45,024 --> 00:08:46,925
763 | There are analogs for
764 |
765 | 191
766 | 00:08:46,993 --> 00:08:49,160
767 | each different kind of interaction with the system
768 |
769 | 192
770 | 00:08:49,229 --> 00:08:51,362
771 | that you might need when VoiceOver is turned on.
772 |
773 | 193
774 | 00:08:51,430 --> 00:08:55,566
775 | So, for instance, with the track scrubber, if I only want
776 |
777 | 194
778 | 00:08:55,635 --> 00:08:57,936
779 | to scrub through the track, if I don't have voice over on,
780 |
781 | 195
782 | 00:08:58,004 --> 00:09:00,137
783 | then I'm just gonna run my finger along it,
784 |
785 | 196
786 | 00:09:00,206 --> 00:09:01,205
787 | like a slider.
788 |
789 | 197
790 | 00:09:01,274 --> 00:09:04,742
791 | But when VoiceOver's on it's trying to
792 |
793 | 198
794 | 00:09:04,811 --> 00:09:07,312
795 | interpret that gesture as me trying to find an element.
796 |
797 | 199
798 | 00:09:07,381 --> 00:09:10,948
799 | So instead we have this adjustable gesture on
800 |
801 | 200
802 | 00:09:11,017 --> 00:09:13,484
803 | items that are adjustable, I can swipe my finger up and
804 |
805 | 201
806 | 00:09:13,553 --> 00:09:20,258
807 | down to change the value.
808 |
809 | 202
810 | 00:09:20,327 --> 00:09:21,926
811 | 8 seconds and 3 minutes.
812 |
813 | 203
814 | 00:09:21,995 --> 00:09:22,961
815 | 30 seconds.
816 |
817 | 204
818 | 00:09:23,030 --> 00:09:24,729
819 | So those are just some very,
820 |
821 | 205
822 | 00:09:24,798 --> 00:09:27,565
823 | very basic examples of how VoiceOver works.
824 |
825 | 206
826 | 00:09:27,634 --> 00:09:29,934
827 | It's much more advanced than that when you get into
828 |
829 | 207
830 | 00:09:30,003 --> 00:09:31,469
831 | the nitty, nitty gritty of it.
832 |
833 | 208
834 | 00:09:31,537 --> 00:09:33,604
835 | And I highly encourage you to turn it on and
836 |
837 | 209
838 | 00:09:33,673 --> 00:09:36,507
839 | play around with it and see what the experience is really
840 |
841 | 210
842 | 00:09:36,576 --> 00:09:38,042
843 | like for a user who's blind.
844 |
845 | 211
846 | 00:09:38,111 --> 00:09:41,245
847 | So where does the information that an assistive technology
848 |
849 | 212
850 | 00:09:41,314 --> 00:09:43,548
851 | like VoiceOver uses coming from?
852 |
853 | 213
854 | 00:09:43,616 --> 00:09:46,785
855 | Well it runs in it's own process on the system, and
856 |
857 | 214
858 | 00:09:46,853 --> 00:09:49,854
859 | it uses the UIAccessibility protocol to communicate with
860 |
861 | 215
862 | 00:09:49,923 --> 00:09:51,288
863 | other processes, and
864 |
865 | 216
866 | 00:09:51,357 --> 00:09:55,960
867 | ask them information about the current element on the screen.
868 |
869 | 217
870 | 00:09:56,029 --> 00:09:57,761
871 | So VoiceOver will receive an input, for
872 |
873 | 218
874 | 00:09:57,830 --> 00:10:00,932
875 | instance a single tap, and
876 |
877 | 219
878 | 00:10:01,000 --> 00:10:03,902
879 | it will get the currently focused element's description.
880 |
881 | 220
882 | 00:10:03,970 --> 00:10:06,805
883 | It will query the current process for predefined pieces
884 |
885 | 221
886 | 00:10:06,873 --> 00:10:09,106
887 | of information about that element.
888 |
889 | 222
890 | 00:10:09,175 --> 00:10:11,842
891 | And from those queries, it's going to stitch together
892 |
893 | 223
894 | 00:10:11,911 --> 00:10:14,079
895 | a user friendly description and speak it.
896 |
897 | 224
898 | 00:10:16,316 --> 00:10:18,649
899 | So let's take a look at the different properties in
900 |
901 | 225
902 | 00:10:18,718 --> 00:10:21,152
903 | the protocol that an assistive technology is going to
904 |
905 | 226
906 | 00:10:21,220 --> 00:10:22,620
907 | ask about.
908 |
909 | 227
910 | 00:10:22,689 --> 00:10:24,689
911 | The first, and arguably most important,
912 |
913 | 228
914 | 00:10:24,757 --> 00:10:27,658
915 | is isAccessibilityElement which tells VoiceOver whether
916 |
917 | 229
918 | 00:10:27,727 --> 00:10:30,928
919 | or not the current thing should even be visible to it.
920 |
921 | 230
922 | 00:10:30,997 --> 00:10:33,664
923 | And if this is set to no then obviously it's not going to be
924 |
925 | 231
926 | 00:10:33,733 --> 00:10:34,699
927 | an accessible element and
928 |
929 | 232
930 | 00:10:34,768 --> 00:10:37,068
931 | VoiceOver will not be able to focus on it.
932 |
933 | 233
934 | 00:10:37,137 --> 00:10:40,572
935 | But in the case of say, a volume slider,
936 |
937 | 234
938 | 00:10:40,641 --> 00:10:42,006
939 | which I'm going to use as an example for
940 |
941 | 235
942 | 00:10:42,075 --> 00:10:44,376
943 | all these properties, we're gonna set this value to true.
944 |
945 | 236
946 | 00:10:46,412 --> 00:10:48,312
947 | Next we have the accessibilityLabel
948 |
949 | 237
950 | 00:10:48,381 --> 00:10:50,915
951 | which describes what an element.
952 |
953 | 238
954 | 00:10:50,984 --> 00:10:55,153
955 | So in the case of the Volume slider, it changes the volume,
956 |
957 | 239
958 | 00:10:55,222 --> 00:10:56,454
959 | so it's going to say Volume.
960 |
961 | 240
962 | 00:10:56,523 --> 00:10:59,524
963 | And then you may wonder
964 |
965 | 241
966 | 00:10:59,593 --> 00:11:02,426
967 | why we don't say something like Volume Slider.
968 |
969 | 242
970 | 00:11:02,495 --> 00:11:03,661
971 | And this is because of this next
972 |
973 | 243
974 | 00:11:03,730 --> 00:11:05,696
975 | property accessibilityTraits
976 |
977 | 244
978 | 00:11:05,765 --> 00:11:09,801
979 | which is used to define what category an element fits into.
980 |
981 | 245
982 | 00:11:09,869 --> 00:11:12,170
983 | So in the case of a slider, it's an adjustable element,
984 |
985 | 246
986 | 00:11:12,239 --> 00:11:14,339
987 | so we're going to give it the adjustable trait.
988 |
989 | 247
990 | 00:11:15,842 --> 00:11:17,542
991 | This means that when VoiceOver describes it,
992 |
993 | 248
994 | 00:11:17,611 --> 00:11:20,511
995 | it's going to say volume adjustable,
996 |
997 | 249
998 | 00:11:20,580 --> 00:11:23,280
999 | which means that the word slider is redundant.
1000 |
1001 | 250
1002 | 00:11:23,349 --> 00:11:24,315
1003 | And doesn't need to be there.
1004 |
1005 | 251
1006 | 00:11:25,752 --> 00:11:26,817
1007 | Accessibility traits
1008 |
1009 | 252
1010 | 00:11:26,886 --> 00:11:29,253
1011 | are important in other ways as well.
1012 |
1013 | 253
1014 | 00:11:29,322 --> 00:11:33,290
1015 | So certain traits afford elements certain behaviors.
1016 |
1017 | 254
1018 | 00:11:33,359 --> 00:11:36,060
1019 | For instance, in my demo where I was showing the track
1020 |
1021 | 255
1022 | 00:11:36,129 --> 00:11:40,331
1023 | scrubber, that increment and decrement gesture is added
1024 |
1025 | 256
1026 | 00:11:40,400 --> 00:11:44,134
1027 | because that view has the adjustable trait set to it.
1028 |
1029 | 257
1030 | 00:11:44,203 --> 00:11:46,771
1031 | So, VoiceOver knows that that view is going to respond
1032 |
1033 | 258
1034 | 00:11:46,839 --> 00:11:50,942
1035 | in some way to having its value increased or decreased.
1036 |
1037 | 259
1038 | 00:11:52,345 --> 00:11:54,545
1039 | VoiceOver also has a mechanism for
1040 |
1041 | 260
1042 | 00:11:54,614 --> 00:11:57,982
1043 | navigating a display, where a user can say
1044 |
1045 | 261
1046 | 00:11:58,050 --> 00:12:01,119
1047 | I want to navigate based on only this kind of item.
1048 |
1049 | 262
1050 | 00:12:01,187 --> 00:12:04,422
1051 | So, for instance, if I had a table view that I wanted to
1052 |
1053 | 263
1054 | 00:12:04,491 --> 00:12:08,593
1055 | navigate just by its headers then I could set this in
1056 |
1057 | 264
1058 | 00:12:08,661 --> 00:12:11,562
1059 | VoiceOver, and it's going to go through and only focus on
1060 |
1061 | 265
1062 | 00:12:11,631 --> 00:12:14,698
1063 | elements in the hierarchy that have the header trait.
1064 |
1065 | 266
1066 | 00:12:14,767 --> 00:12:17,001
1067 | So it's important that all of your views have the right
1068 |
1069 | 267
1070 | 00:12:17,070 --> 00:12:19,971
1071 | traits so they behave as expected to voice over users.
1072 |
1073 | 268
1074 | 00:12:22,375 --> 00:12:24,442
1075 | Next we have accessibility value.
1076 |
1077 | 269
1078 | 00:12:24,511 --> 00:12:27,745
1079 | Which you can override if your view has some sort of state.
1080 |
1081 | 270
1082 | 00:12:27,814 --> 00:12:29,747
1083 | So for example, the state for
1084 |
1085 | 271
1086 | 00:12:29,816 --> 00:12:32,283
1087 | the volume slider is what is the current percent
1088 |
1089 | 272
1090 | 00:12:32,352 --> 00:12:35,219
1091 | that my volume is set to, and we're gonna return 50%.
1092 |
1093 | 273
1094 | 00:12:35,288 --> 00:12:39,757
1095 | And finally, we have accessibilityHint.
1096 |
1097 | 274
1098 | 00:12:39,825 --> 00:12:42,593
1099 | So this is another optional property that's meant
1100 |
1101 | 275
1102 | 00:12:42,662 --> 00:12:45,129
1103 | to provide a more long-form description of what something
1104 |
1105 | 276
1106 | 00:12:45,198 --> 00:12:47,398
1107 | is or what something does.
1108 |
1109 | 277
1110 | 00:12:47,467 --> 00:12:51,035
1111 | This is important often for VoiceOver users who have never
1112 |
1113 | 278
1114 | 00:12:51,104 --> 00:12:53,705
1115 | used your interface before and are trying to learn their way
1116 |
1117 | 279
1118 | 00:12:53,773 --> 00:12:57,575
1119 | around it and figure out how things work together.
1120 |
1121 | 280
1122 | 00:12:57,643 --> 00:13:00,211
1123 | But you should never put information that is
1124 |
1125 | 281
1126 | 00:13:00,280 --> 00:13:03,381
1127 | critical to the user in this description
1128 |
1129 | 282
1130 | 00:13:03,450 --> 00:13:06,384
1131 | because Accessibility can be turned off.
1132 |
1133 | 283
1134 | 00:13:06,452 --> 00:13:08,619
1135 | And therefore a user may not ever hear them.
1136 |
1137 | 284
1138 | 00:13:08,688 --> 00:13:11,756
1139 | Which they might do to keep VoiceOver from being
1140 |
1141 | 285
1142 | 00:13:11,825 --> 00:13:14,825
1143 | too verbose if they're an experienced user.
1144 |
1145 | 286
1146 | 00:13:14,894 --> 00:13:18,662
1147 | So those are the fine five main accessibility traits.
1148 |
1149 | 287
1150 | 00:13:18,731 --> 00:13:21,599
1151 | Without them the interface is totally unusable to VoiceOver,
1152 |
1153 | 288
1154 | 00:13:21,667 --> 00:13:25,036
1155 | and that's the blind and low vision users who rely on it.
1156 |
1157 | 289
1158 | 00:13:25,104 --> 00:13:29,674
1159 | UIKit views define these properties by default, or
1160 |
1161 | 290
1162 | 00:13:29,742 --> 00:13:32,543
1163 | most of them do, which means that most of the legwork is
1164 |
1165 | 291
1166 | 00:13:32,611 --> 00:13:34,078
1167 | already done for you.
1168 |
1169 | 292
1170 | 00:13:34,147 --> 00:13:35,612
1171 | But what you really need to watch out for
1172 |
1173 | 293
1174 | 00:13:35,681 --> 00:13:39,551
1175 | is your own custom views, so let's look at some code.
1176 |
1177 | 294
1178 | 00:13:41,154 --> 00:13:43,788
1179 | Let's say that I have a view controller
1180 |
1181 | 295
1182 | 00:13:43,856 --> 00:13:47,925
1183 | that has a property image view of subclass MyImageView,
1184 |
1185 | 296
1186 | 00:13:47,994 --> 00:13:50,695
1187 | which is a subclass that I've created.
1188 |
1189 | 297
1190 | 00:13:50,764 --> 00:13:52,764
1191 | It's just a UIView, it's not a UIImageView or
1192 |
1193 | 298
1194 | 00:13:52,832 --> 00:13:54,131
1195 | anything like that, so
1196 |
1197 | 299
1198 | 00:13:54,200 --> 00:13:55,767
1199 | it doesn't have accessibility by default.
1200 |
1201 | 300
1202 | 00:13:57,437 --> 00:13:59,436
1203 | Well in my viewDidLoad method I'm obviously gonna call
1204 |
1205 | 301
1206 | 00:13:59,505 --> 00:14:01,572
1207 | super and then I could do this.
1208 |
1209 | 302
1210 | 00:14:01,640 --> 00:14:04,342
1211 | I could use dot notation to set each of these different
1212 |
1213 | 303
1214 | 00:14:04,411 --> 00:14:05,275
1215 | properties.
1216 |
1217 | 304
1218 | 00:14:05,344 --> 00:14:06,277
1219 | I'm gonna say yes my
1220 |
1221 | 305
1222 | 00:14:06,345 --> 00:14:08,179
1223 | imageView.isAccessibilityElem- ent.
1224 |
1225 | 306
1226 | 00:14:08,248 --> 00:14:12,550
1227 | I'm gonna give it some reasonable label and I'm gonna
1228 |
1229 | 307
1230 | 00:14:12,618 --> 00:14:15,185
1231 | give it the trait, the image trait, because I want it to
1232 |
1233 | 308
1234 | 00:14:15,254 --> 00:14:17,322
1235 | behave like any other image would on the system.
1236 |
1237 | 309
1238 | 00:14:18,658 --> 00:14:21,258
1239 | Now, I probably want to do this in a case where these
1240 |
1241 | 310
1242 | 00:14:21,327 --> 00:14:25,963
1243 | values depend on an instance of a view.
1244 |
1245 | 311
1246 | 00:14:26,032 --> 00:14:28,565
1247 | But, there may be a case where
1248 |
1249 | 312
1250 | 00:14:28,634 --> 00:14:31,602
1251 | the value that is returned from one of these properties
1252 |
1253 | 313
1254 | 00:14:31,671 --> 00:14:33,270
1255 | applies to all view of that kind.
1256 |
1257 | 314
1258 | 00:14:33,339 --> 00:14:37,475
1259 | So, on the subclass MyImageView,
1260 |
1261 | 315
1262 | 00:14:37,544 --> 00:14:41,879
1263 | I could have instead overridden the getter for
1264 |
1265 | 316
1266 | 00:14:41,948 --> 00:14:45,182
1267 | isAccessibilityElement always return true.
1268 |
1269 | 317
1270 | 00:14:45,251 --> 00:14:47,451
1271 | If I know that MyImageView is never not
1272 |
1273 | 318
1274 | 00:14:47,520 --> 00:14:48,585
1275 | going to be an accessibility
1276 |
1277 | 319
1278 | 00:14:48,654 --> 00:14:50,588
1279 | element than this is probably what I want to do.
1280 |
1281 | 320
1282 | 00:14:50,657 --> 00:14:53,791
1283 | Or if there's some internal logic to that class that
1284 |
1285 | 321
1286 | 00:14:53,860 --> 00:14:55,793
1287 | determines whether or not I should determine true or
1288 |
1289 | 322
1290 | 00:14:55,862 --> 00:14:58,762
1291 | false from here, this is a much better way to do that.
1292 |
1293 | 323
1294 | 00:14:58,831 --> 00:15:00,899
1295 | And then I can override the setter to just do nothing
1296 |
1297 | 324
1298 | 00:15:02,435 --> 00:15:04,802
1299 | this applies to all of the properties.
1300 |
1301 | 325
1302 | 00:15:04,871 --> 00:15:06,570
1303 | I can override them, their getters and
1304 |
1305 | 326
1306 | 00:15:06,639 --> 00:15:07,639
1307 | setters explicitly.
1308 |
1309 | 327
1310 | 00:15:10,510 --> 00:15:13,444
1311 | So, now I'd like to demo what you've just seen
1312 |
1313 | 328
1314 | 00:15:13,513 --> 00:15:14,945
1315 | on a sample app that I've been working on.
1316 |
1317 | 329
1318 | 00:15:15,014 --> 00:15:19,349
1319 | So I'm gonna go back over here to my device and
1320 |
1321 | 330
1322 | 00:15:19,418 --> 00:15:20,618
1323 | I'm gonna turn VoiceOver back on.
1324 |
1325 | 331
1326 | 00:15:21,788 --> 00:15:22,353
1327 | VoiceOver on.
1328 |
1329 | 332
1330 | 00:15:23,789 --> 00:15:26,257
1331 | So you see down here I have this app called Notecards.
1332 |
1333 | 333
1334 | 00:15:26,326 --> 00:15:28,626
1335 | [INAUDIBLE] Note note cards.
1336 |
1337 | 334
1338 | 00:15:28,694 --> 00:15:33,264
1339 | It's just a basic app that has stacks of notecards that I
1340 |
1341 | 335
1342 | 00:15:33,333 --> 00:15:35,232
1343 | can use to test myself.
1344 |
1345 | 336
1346 | 00:15:35,301 --> 00:15:37,535
1347 | And I need to do an accessibility audit of this
1348 |
1349 | 337
1350 | 00:15:37,603 --> 00:15:40,104
1351 | app to see how well it works with VoiceOver.
1352 |
1353 | 338
1354 | 00:15:40,172 --> 00:15:42,139
1355 | So, I'm gonna start by tapping on the first thing I see,
1356 |
1357 | 339
1358 | 00:15:42,208 --> 00:15:43,207
1359 | which is that collection header.
1360 |
1361 | 340
1362 | 00:15:43,276 --> 00:15:46,010
1363 | Collection.
1364 |
1365 | 341
1366 | 00:15:46,079 --> 00:15:50,814
1367 | So, as you saw it read the label collection but
1368 |
1369 | 342
1370 | 00:15:50,883 --> 00:15:52,583
1371 | what it didn't say was header.
1372 |
1373 | 343
1374 | 00:15:52,651 --> 00:15:54,952
1375 | So I have no idea that this thing
1376 |
1377 | 344
1378 | 00:15:55,021 --> 00:15:57,488
1379 | is actually a label that is meant to be a header for
1380 |
1381 | 345
1382 | 00:15:57,557 --> 00:15:58,789
1383 | all of the content underneath it.
1384 |
1385 | 346
1386 | 00:15:58,858 --> 00:16:01,125
1387 | So that's the first thing I need to do is add that trait.
1388 |
1389 | 347
1390 | 00:16:02,629 --> 00:16:03,294
1391 | Add button.
1392 |
1393 | 348
1394 | 00:16:03,362 --> 00:16:05,329
1395 | That button has a sensible label.
1396 |
1397 | 349
1398 | 00:16:05,398 --> 00:16:07,198
1399 | Physics five cards.
1400 |
1401 | 350
1402 | 00:16:07,267 --> 00:16:07,865
1403 | That seems right.
1404 |
1405 | 351
1406 | 00:16:07,934 --> 00:16:10,834
1407 | Image one button.
1408 |
1409 | 352
1410 | 00:16:10,903 --> 00:16:11,702
1411 | That doesn't seem right.
1412 |
1413 | 353
1414 | 00:16:11,771 --> 00:16:14,038
1415 | Image two button.
1416 |
1417 | 354
1418 | 00:16:14,107 --> 00:16:17,008
1419 | And neither does that so both of these buttons
1420 |
1421 | 355
1422 | 00:16:17,077 --> 00:16:19,243
1423 | are missing accessibility labels and so
1424 |
1425 | 356
1426 | 00:16:19,312 --> 00:16:21,745
1427 | I have actually no idea what they do.
1428 |
1429 | 357
1430 | 00:16:21,814 --> 00:16:24,949
1431 | And it said image one and two because VoiceOver
1432 |
1433 | 358
1434 | 00:16:25,017 --> 00:16:28,252
1435 | by default when it doesn't have a label on something that
1436 |
1437 | 359
1438 | 00:16:28,321 --> 00:16:32,389
1439 | uses an image like a UIButton, it's going to default to that
1440 |
1441 | 360
1442 | 00:16:32,458 --> 00:16:36,027
1443 | image's filename as a last resort to try and see if it
1444 |
1445 | 361
1446 | 00:16:36,095 --> 00:16:38,829
1447 | can get something meaningful out of what this element is.
1448 |
1449 | 362
1450 | 00:16:38,897 --> 00:16:42,533
1451 | So I need to instead add my own labels to those buttons.
1452 |
1453 | 363
1454 | 00:16:42,602 --> 00:16:47,137
1455 | Trivia, nine trivia.
1456 |
1457 | 364
1458 | 00:16:47,206 --> 00:16:47,939
1459 | Now if I go in here,
1460 |
1461 | 365
1462 | 00:16:48,008 --> 00:16:50,307
1463 | I heard that that had the header trait.
1464 |
1465 | 366
1466 | 00:16:50,376 --> 00:16:52,276
1467 | Add button.
1468 |
1469 | 367
1470 | 00:16:52,344 --> 00:16:53,076
1471 | That has a good label.
1472 |
1473 | 368
1474 | 00:16:53,145 --> 00:16:55,513
1475 | Close button.
1476 |
1477 | 369
1478 | 00:16:55,581 --> 00:16:56,447
1479 | And if I come in here.
1480 |
1481 | 370
1482 | 00:16:56,516 --> 00:16:58,482
1483 | The phrase "Let them eat cake" is commonly
1484 |
1485 | 371
1486 | 00:16:58,551 --> 00:16:59,450
1487 | attributed to whom?
1488 |
1489 | 372
1490 | 00:16:59,519 --> 00:17:00,551
1491 | Queen Marie Antoinette.
1492 |
1493 | 373
1494 | 00:17:00,620 --> 00:17:02,119
1495 | I notice that these two labels,
1496 |
1497 | 374
1498 | 00:17:02,188 --> 00:17:04,388
1499 | even though VoiceOver's picking them up,
1500 |
1501 | 375
1502 | 00:17:04,457 --> 00:17:07,124
1503 | they are picked up as separate elements and so, I don't
1504 |
1505 | 376
1506 | 00:17:07,193 --> 00:17:10,094
1507 | really have any context for how they work together.
1508 |
1509 | 377
1510 | 00:17:10,163 --> 00:17:11,862
1511 | One is the question and one is the answer.
1512 |
1513 | 378
1514 | 00:17:11,930 --> 00:17:14,865
1515 | And it would actually be much better and give VoiceOver
1516 |
1517 | 379
1518 | 00:17:14,934 --> 00:17:17,735
1519 | users much context if I were to group them together.
1520 |
1521 | 380
1522 | 00:17:17,803 --> 00:17:18,636
1523 | That's one element and
1524 |
1525 | 381
1526 | 00:17:18,705 --> 00:17:21,405
1527 | say this is the question, this is the answer.
1528 |
1529 | 382
1530 | 00:17:21,473 --> 00:17:23,107
1531 | So they can actually understand what's happening in
1532 |
1533 | 383
1534 | 00:17:23,175 --> 00:17:24,575
1535 | this interface.
1536 |
1537 | 384
1538 | 00:17:24,644 --> 00:17:27,845
1539 | So I'm gonna go over to some code, to my app.
1540 |
1541 | 385
1542 | 00:17:27,913 --> 00:17:31,282
1543 | The first thing I wanna take care of is that header trade
1544 |
1545 | 386
1546 | 00:17:31,350 --> 00:17:32,016
1547 | cuz it's pretty easy.
1548 |
1549 | 387
1550 | 00:17:32,085 --> 00:17:36,853
1551 | And I have this title label right here, so
1552 |
1553 | 388
1554 | 00:17:36,922 --> 00:17:43,628
1555 | I'm going to say accessibility traits or equals header.
1556 |
1557 | 389
1558 | 00:17:43,696 --> 00:17:46,430
1559 | Now I'm using or equals instead of just explicitly
1560 |
1561 | 390
1562 | 00:17:46,498 --> 00:17:51,101
1563 | equals, because I don't know what the superclass of title
1564 |
1565 | 391
1566 | 00:17:51,170 --> 00:17:54,071
1567 | label, what traits it is added to
1568 |
1569 | 392
1570 | 00:17:54,140 --> 00:17:56,774
1571 | this accessibility element that it wants to have there.
1572 |
1573 | 393
1574 | 00:17:56,843 --> 00:17:58,642
1575 | So I don't wanna override whatever it set.
1576 |
1577 | 394
1578 | 00:17:58,711 --> 00:18:00,044
1579 | I just wanna add my own in.
1580 |
1581 | 395
1582 | 00:18:00,113 --> 00:18:03,114
1583 | So that's what I'm doing there.
1584 |
1585 | 396
1586 | 00:18:03,182 --> 00:18:07,918
1587 | Next, let's look at this cell and the shuffle, and
1588 |
1589 | 397
1590 | 00:18:07,987 --> 00:18:09,453
1591 | delete button.
1592 |
1593 | 398
1594 | 00:18:09,522 --> 00:18:13,357
1595 | So I need to add accessibility labels for
1596 |
1597 | 399
1598 | 00:18:13,426 --> 00:18:15,893
1599 | these and come here and say
1600 |
1601 | 400
1602 | 00:18:15,961 --> 00:18:20,064
1603 | shuffleButton.accessibilityLa- bel.
1604 |
1605 | 401
1606 | 00:18:22,101 --> 00:18:24,701
1607 | Shuffle seems like a reasonable label to give it.
1608 |
1609 | 402
1610 | 00:18:24,770 --> 00:18:29,841
1611 | I'm gonna say delete button equals delete.
1612 |
1613 | 403
1614 | 00:18:31,577 --> 00:18:34,845
1615 | This seems to convey to me what exactly these buttons
1616 |
1617 | 404
1618 | 00:18:34,914 --> 00:18:36,147
1619 | are supposed to do.
1620 |
1621 | 405
1622 | 00:18:36,215 --> 00:18:38,349
1623 | And finally, I'm gonna come to this collection view cell
1624 |
1625 | 406
1626 | 00:18:38,417 --> 00:18:40,518
1627 | to have this question and answer.
1628 |
1629 | 407
1630 | 00:18:40,586 --> 00:18:41,752
1631 | What I'm gonna do here
1632 |
1633 | 408
1634 | 00:18:43,890 --> 00:18:49,393
1635 | is override these methods or these properties.
1636 |
1637 | 409
1638 | 00:18:49,461 --> 00:18:51,095
1639 | So I'm gonna override this accessibility element to
1640 |
1641 | 410
1642 | 00:18:51,164 --> 00:18:53,764
1643 | always return true on the cell itself so
1644 |
1645 | 411
1646 | 00:18:53,832 --> 00:18:56,000
1647 | that the entire cell has the accessibility element
1648 |
1649 | 412
1650 | 00:18:56,068 --> 00:18:57,301
1651 | instead of each individual label.
1652 |
1653 | 413
1654 | 00:18:57,369 --> 00:19:01,471
1655 | I'm gonna set the label to return Question,
1656 |
1657 | 414
1658 | 00:19:01,540 --> 00:19:03,374
1659 | then the question's text.
1660 |
1661 | 415
1662 | 00:19:03,443 --> 00:19:05,543
1663 | Answer, and then the answer's text.
1664 |
1665 | 416
1666 | 00:19:05,611 --> 00:19:07,611
1667 | And I'm going to add the button trait to it because
1668 |
1669 | 417
1670 | 00:19:07,680 --> 00:19:10,414
1671 | that cell is a button where I can go in and edit the card.
1672 |
1673 | 418
1674 | 00:19:11,917 --> 00:19:14,018
1675 | And I need to convey that to the user.
1676 |
1677 | 419
1678 | 00:19:16,255 --> 00:19:17,255
1679 | So let's build this.
1680 |
1681 | 420
1682 | 00:19:19,358 --> 00:19:20,191
1683 | Notecards.
1684 |
1685 | 421
1686 | 00:19:22,795 --> 00:19:26,129
1687 | [SOUND] Notecards, collections heading.
1688 |
1689 | 422
1690 | 00:19:26,198 --> 00:19:27,197
1691 | So I've got the header trait.
1692 |
1693 | 423
1694 | 00:19:27,266 --> 00:19:32,836
1695 | Tab physics shuffle button delete button.
1696 |
1697 | 424
1698 | 00:19:32,905 --> 00:19:34,638
1699 | Both buttons have the right labels.
1700 |
1701 | 425
1702 | 00:19:34,707 --> 00:19:38,942
1703 | Trivia, link trivia, trivia question: the phrase "Let them
1704 |
1705 | 426
1706 | 00:19:39,011 --> 00:19:41,945
1707 | eat cake" is commonly attributed to whom?
1708 |
1709 | 427
1710 | 00:19:42,014 --> 00:19:44,448
1711 | Answer Queen Marie Antoinette.
1712 |
1713 | 428
1714 | 00:19:44,517 --> 00:19:47,417
1715 | So, I've got it behaving exactly as I want it,
1716 |
1717 | 429
1718 | 00:19:47,486 --> 00:19:50,220
1719 | just a few simple lines of code.
1720 |
1721 | 430
1722 | 00:19:50,289 --> 00:19:53,023
1723 | That's just a couple examples of some of the issues that you
1724 |
1725 | 431
1726 | 00:19:53,092 --> 00:19:54,325
1727 | might find in your own apps.
1728 |
1729 | 432
1730 | 00:19:55,528 --> 00:19:58,129
1731 | So I'm gonna go back, to my account.
1732 |
1733 | 433
1734 | 00:20:00,933 --> 00:20:06,069
1735 | I also would like to touch on- VoiceOver off.
1736 |
1737 | 434
1738 | 00:20:06,138 --> 00:20:08,906
1739 | The idea of containers.
1740 |
1741 | 435
1742 | 00:20:08,975 --> 00:20:11,042
1743 | So aside from the attributes.
1744 |
1745 | 436
1746 | 00:20:12,711 --> 00:20:16,113
1747 | We also have the accessibility container protocol.
1748 |
1749 | 437
1750 | 00:20:16,182 --> 00:20:17,648
1751 | So let's say that I am the engineer who has been
1752 |
1753 | 438
1754 | 00:20:17,716 --> 00:20:20,150
1755 | tasked with coding this view in the Calendar app,
1756 |
1757 | 439
1758 | 00:20:20,219 --> 00:20:21,618
1759 | it's the year view.
1760 |
1761 | 440
1762 | 00:20:21,687 --> 00:20:25,156
1763 | And I've decided that I am going to design this view so
1764 |
1765 | 441
1766 | 00:20:25,225 --> 00:20:29,093
1767 | that each week is its own custom UIView.
1768 |
1769 | 442
1770 | 00:20:29,162 --> 00:20:31,561
1771 | And within that UIView's drawRect method,
1772 |
1773 | 443
1774 | 00:20:31,630 --> 00:20:35,232
1775 | I'm going to explicitly draw all the days of the week.
1776 |
1777 | 444
1778 | 00:20:35,301 --> 00:20:38,035
1779 | Now because those views that I've drawn aren't standard
1780 |
1781 | 445
1782 | 00:20:38,104 --> 00:20:39,337
1783 | UIKit views,
1784 |
1785 | 446
1786 | 00:20:39,405 --> 00:20:42,106
1787 | they don't inherit accessibility by default.
1788 |
1789 | 447
1790 | 00:20:42,175 --> 00:20:46,043
1791 | And I don't really have an easy way of setting
1792 |
1793 | 448
1794 | 00:20:46,112 --> 00:20:48,246
1795 | the accessibility properties on each of them.
1796 |
1797 | 449
1798 | 00:20:50,182 --> 00:20:50,948
1799 | But what we'd like for
1800 |
1801 | 450
1802 | 00:20:51,017 --> 00:20:53,984
1803 | them to be is visible to VoiceOver one day at a time.
1804 |
1805 | 451
1806 | 00:20:54,053 --> 00:20:56,920
1807 | And so that I can navigate them day by day and
1808 |
1809 | 452
1810 | 00:20:56,989 --> 00:20:59,656
1811 | get a description for each day at a time,
1812 |
1813 | 453
1814 | 00:20:59,725 --> 00:21:01,458
1815 | rather than each week at a time.
1816 |
1817 | 454
1818 | 00:21:01,527 --> 00:21:04,795
1819 | So I need to do is create a set of accessibility elements
1820 |
1821 | 455
1822 | 00:21:04,864 --> 00:21:07,364
1823 | from scratch that overlay these day views and
1824 |
1825 | 456
1826 | 00:21:07,433 --> 00:21:10,700
1827 | return them as sub-elements of my accessibility, or
1828 |
1829 | 457
1830 | 00:21:10,769 --> 00:21:12,503
1831 | of my week view container.
1832 |
1833 | 458
1834 | 00:21:14,540 --> 00:21:16,573
1835 | So what does that look like in code?
1836 |
1837 | 459
1838 | 00:21:16,642 --> 00:21:19,710
1839 | Well, I have this MyWeekView class.
1840 |
1841 | 460
1842 | 00:21:19,779 --> 00:21:22,913
1843 | Which I'm going to explicitly say is not an accessibility
1844 |
1845 | 461
1846 | 00:21:22,982 --> 00:21:26,150
1847 | element, because I instead want VoiceOver to go through
1848 |
1849 | 462
1850 | 00:21:26,219 --> 00:21:29,320
1851 | and find the sub-elements of it that are accessible.
1852 |
1853 | 463
1854 | 00:21:31,690 --> 00:21:34,625
1855 | And I'm going to create an array of elements that
1856 |
1857 | 464
1858 | 00:21:34,694 --> 00:21:37,661
1859 | are UIAccessibilityElement.
1860 |
1861 | 465
1862 | 00:21:37,730 --> 00:21:39,797
1863 | I'm going to iterate over the days of the week that
1864 |
1865 | 466
1866 | 00:21:39,866 --> 00:21:41,432
1867 | are in that week.
1868 |
1869 | 467
1870 | 00:21:41,501 --> 00:21:44,401
1871 | And for each one I'm going to create an accessibility
1872 |
1873 | 468
1874 | 00:21:44,470 --> 00:21:47,537
1875 | element, with the accessibility container set
1876 |
1877 | 469
1878 | 00:21:47,606 --> 00:21:50,207
1879 | as myself, because I'm the one that contains it.
1880 |
1881 | 470
1882 | 00:21:50,276 --> 00:21:52,776
1883 | I'm going to set its label to be something
1884 |
1885 | 471
1886 | 00:21:52,844 --> 00:21:53,677
1887 | sensible for that day.
1888 |
1889 | 472
1890 | 00:21:53,746 --> 00:21:55,913
1891 | And now I'm going to set this property
1892 |
1893 | 473
1894 | 00:21:55,982 --> 00:21:58,648
1895 | accessibilityFrameInContainer- Space.
1896 |
1897 | 474
1898 | 00:21:58,717 --> 00:22:01,618
1899 | Now, this is crucial because it indicates to VoiceOver
1900 |
1901 | 475
1902 | 00:22:01,687 --> 00:22:04,721
1903 | where the element is on the screen, so that when I'm
1904 |
1905 | 476
1906 | 00:22:04,790 --> 00:22:09,760
1907 | panning around with my finger VoiceOver knows where it is.
1908 |
1909 | 477
1910 | 00:22:09,828 --> 00:22:12,863
1911 | So if my finger is over it, it can describe it to me and
1912 |
1913 | 478
1914 | 00:22:12,931 --> 00:22:14,965
1915 | see that I'm trying to focus on that element.
1916 |
1917 | 479
1918 | 00:22:15,033 --> 00:22:17,368
1919 | It's also what VoiceOver uses to draw the bounding box.
1920 |
1921 | 480
1922 | 00:22:19,805 --> 00:22:23,073
1923 | And in case you couldn't tell this frame should be in
1924 |
1925 | 481
1926 | 00:22:23,142 --> 00:22:24,809
1927 | the coordinate space of its container.
1928 |
1929 | 482
1930 | 00:22:26,278 --> 00:22:30,681
1931 | So once I do that, I'll pan the element to my array of
1932 |
1933 | 483
1934 | 00:22:30,750 --> 00:22:33,650
1935 | accessibility elements, and then, I will set the property
1936 |
1937 | 484
1938 | 00:22:33,719 --> 00:22:37,488
1939 | on MyWeekView accessibility elements to be those elements.
1940 |
1941 | 485
1942 | 00:22:37,556 --> 00:22:41,325
1943 | And what this says is these are all my accessible
1944 |
1945 | 486
1946 | 00:22:41,394 --> 00:22:45,228
1947 | sub-elements and VoiceOver should navigate them
1948 |
1949 | 487
1950 | 00:22:45,297 --> 00:22:48,065
1951 | in the order that I returned them in this array.
1952 |
1953 | 488
1954 | 00:22:49,868 --> 00:22:52,202
1955 | So, let's take a look at adding that to my sample app.
1956 |
1957 | 489
1958 | 00:22:52,271 --> 00:22:55,106
1959 | Let me go back over here.
1960 |
1961 | 490
1962 | 00:22:56,976 --> 00:22:58,008
1963 | And turn the VoiceOver back on.
1964 |
1965 | 491
1966 | 00:22:58,077 --> 00:23:02,479
1967 | VoiceOver on now.
1968 |
1969 | 492
1970 | 00:23:02,548 --> 00:23:03,814
1971 | So you may have wondered
1972 |
1973 | 493
1974 | 00:23:03,883 --> 00:23:05,582
1975 | what this shuffle button actually does.
1976 |
1977 | 494
1978 | 00:23:05,651 --> 00:23:09,286
1979 | Well, it shuffles the cards in the deck and puts them up so
1980 |
1981 | 495
1982 | 00:23:09,354 --> 00:23:09,886
1983 | I can test them.
1984 |
1985 | 496
1986 | 00:23:09,955 --> 00:23:14,257
1987 | Shuffle trivia heading.
1988 |
1989 | 497
1990 | 00:23:14,326 --> 00:23:15,426
1991 | And what I have down here,
1992 |
1993 | 498
1994 | 00:23:15,495 --> 00:23:19,163
1995 | this little circle view is just a little UI to
1996 |
1997 | 499
1998 | 00:23:19,231 --> 00:23:22,099
1999 | indicate to me how far I am through the deck.
2000 |
2001 | 500
2002 | 00:23:22,167 --> 00:23:25,369
2003 | So if I go to the next card for instance- Next question.
2004 |
2005 | 501
2006 | 00:23:25,437 --> 00:23:28,205
2007 | It's increasing because I'm filling out the circle
2008 |
2009 | 502
2010 | 00:23:28,274 --> 00:23:29,974
2011 | with how many cards I've done.
2012 |
2013 | 503
2014 | 00:23:30,042 --> 00:23:31,909
2015 | However if I stay to swipe to it.
2016 |
2017 | 504
2018 | 00:23:31,977 --> 00:23:34,544
2019 | Next question, from next question.
2020 |
2021 | 505
2022 | 00:23:34,613 --> 00:23:36,013
2023 | I hear a bonk and
2024 |
2025 | 506
2026 | 00:23:36,081 --> 00:23:40,083
2027 | try to run my finger I'm also hearing a bonk.
2028 |
2029 | 507
2030 | 00:23:40,152 --> 00:23:43,186
2031 | So what that indicates is that when I swiped and
2032 |
2033 | 508
2034 | 00:23:43,255 --> 00:23:46,590
2035 | did it it means there's nothing left on the screen for
2036 |
2037 | 509
2038 | 00:23:46,658 --> 00:23:49,093
2039 | VoiceOver to swipe to you've hit the last element.
2040 |
2041 | 510
2042 | 00:23:49,161 --> 00:23:50,961
2043 | And when I'm running my finger over it means that there's
2044 |
2045 | 511
2046 | 00:23:51,030 --> 00:23:53,797
2047 | nothing below my finger that is an accessible element.
2048 |
2049 | 512
2050 | 00:23:53,866 --> 00:23:56,900
2051 | But we'd really like that to be accessible to VoiceOver
2052 |
2053 | 513
2054 | 00:23:56,969 --> 00:23:59,837
2055 | users, so they can track their progress through this stack.
2056 |
2057 | 514
2058 | 00:23:59,905 --> 00:24:01,004
2059 | And so we're gonna use
2060 |
2061 | 515
2062 | 00:24:01,073 --> 00:24:05,109
2063 | accessibility elements to accomplish this.
2064 |
2065 | 516
2066 | 00:24:05,178 --> 00:24:07,911
2067 | So I'm gonna come back over to my code.
2068 |
2069 | 517
2070 | 00:24:07,980 --> 00:24:09,913
2071 | I'm gonna go to this ShuffleStatusView,
2072 |
2073 | 518
2074 | 00:24:09,982 --> 00:24:12,616
2075 | which is where I've done the drawing of this circle.
2076 |
2077 | 519
2078 | 00:24:15,454 --> 00:24:16,954
2079 | I'm gonna copy and paste.
2080 |
2081 | 520
2082 | 00:24:22,561 --> 00:24:24,528
2083 | So, what I've done here is I've created
2084 |
2085 | 521
2086 | 00:24:24,597 --> 00:24:27,731
2087 | an AccessibilityElement with myself as the container.
2088 |
2089 | 522
2090 | 00:24:27,800 --> 00:24:30,901
2091 | I set its label to be card, whatever the current card
2092 |
2093 | 523
2094 | 00:24:30,970 --> 00:24:33,937
2095 | number is, of the total amount of cards.
2096 |
2097 | 524
2098 | 00:24:34,006 --> 00:24:36,072
2099 | I've set its accessibilityFrame
2100 |
2101 | 525
2102 | 00:24:36,141 --> 00:24:37,875
2103 | to be the frame of the circle.
2104 |
2105 | 526
2106 | 00:24:37,944 --> 00:24:40,411
2107 | And in my AccessibilityElements because
2108 |
2109 | 527
2110 | 00:24:40,479 --> 00:24:41,412
2111 | the previous and
2112 |
2113 | 528
2114 | 00:24:41,480 --> 00:24:44,114
2115 | next button are also part of the StatusView,
2116 |
2117 | 529
2118 | 00:24:44,183 --> 00:24:47,083
2119 | I don't want them to be left out from VoiceOver.
2120 |
2121 | 530
2122 | 00:24:47,152 --> 00:24:48,885
2123 | So I'm gonna also include those in my
2124 |
2125 | 531
2126 | 00:24:48,954 --> 00:24:51,621
2127 | AccessibilityElements along with the new element that
2128 |
2129 | 532
2130 | 00:24:51,690 --> 00:24:52,656
2131 | I've just created.
2132 |
2133 | 533
2134 | 00:24:52,725 --> 00:24:55,425
2135 | So let's see if that worked.
2136 |
2137 | 534
2138 | 00:24:55,494 --> 00:24:58,329
2139 | NoteCards, NoteCards, collect,
2140 |
2141 | 535
2142 | 00:24:58,397 --> 00:25:03,100
2143 | shuffle button, shuffle, trivia, previous question.
2144 |
2145 | 536
2146 | 00:25:03,169 --> 00:25:04,368
2147 | I've got my previous button.
2148 |
2149 | 537
2150 | 00:25:07,373 --> 00:25:12,175
2151 | Next question, problem, part one of nine.
2152 |
2153 | 538
2154 | 00:25:12,244 --> 00:25:14,211
2155 | So now it's become accessible.
2156 |
2157 | 539
2158 | 00:25:14,279 --> 00:25:18,048
2159 | And pretty easy, not too many lines of code.
2160 |
2161 | 540
2162 | 00:25:18,116 --> 00:25:19,383
2163 | We can go back.
2164 |
2165 | 541
2166 | 00:25:21,687 --> 00:25:24,321
2167 | So I'd like to change gears for a minute, and
2168 |
2169 | 542
2170 | 00:25:24,390 --> 00:25:28,792
2171 | talk a little bit about some visual accommodations that you
2172 |
2173 | 543
2174 | 00:25:28,860 --> 00:25:30,594
2175 | should be aware of when you're designing your app.
2176 |
2177 | 544
2178 | 00:25:31,897 --> 00:25:34,364
2179 | So the first thing is color.
2180 |
2181 | 545
2182 | 00:25:34,433 --> 00:25:37,701
2183 | Color is a useful means of differentiating information,
2184 |
2185 | 546
2186 | 00:25:37,769 --> 00:25:40,537
2187 | but if it's the sole differentiator
2188 |
2189 | 547
2190 | 00:25:40,606 --> 00:25:43,139
2191 | then users who are colorblind won't be able to fully
2192 |
2193 | 548
2194 | 00:25:43,208 --> 00:25:44,974
2195 | understand the user interface.
2196 |
2197 | 549
2198 | 00:25:45,043 --> 00:25:47,644
2199 | So, take for example this view in Mail.
2200 |
2201 | 550
2202 | 00:25:47,712 --> 00:25:50,714
2203 | Our designers wanted the unread and
2204 |
2205 | 551
2206 | 00:25:50,783 --> 00:25:54,184
2207 | flagged messages to be differentiated apart from each
2208 |
2209 | 552
2210 | 00:25:54,253 --> 00:25:58,288
2211 | other with circle views that are of a particular color.
2212 |
2213 | 553
2214 | 00:25:58,356 --> 00:26:01,691
2215 | But to a colorblind user, they can't tell the difference.
2216 |
2217 | 554
2218 | 00:26:01,760 --> 00:26:05,695
2219 | So what we did, is we added a setting in Mail so that you
2220 |
2221 | 555
2222 | 00:26:05,764 --> 00:26:10,533
2223 | can change flag messages to use shape and color.
2224 |
2225 | 556
2226 | 00:26:10,602 --> 00:26:14,204
2227 | And what this does is it uses both color and shape to convey
2228 |
2229 | 557
2230 | 00:26:14,272 --> 00:26:16,906
2231 | meaning so that no user has to be left out.
2232 |
2233 | 558
2234 | 00:26:16,975 --> 00:26:19,576
2235 | So, if you're writing an app that uses color to
2236 |
2237 | 559
2238 | 00:26:19,644 --> 00:26:20,343
2239 | convey meaning,
2240 |
2241 | 560
2242 | 00:26:20,412 --> 00:26:22,046
2243 | then you should consider doing something similar.
2244 |
2245 | 561
2246 | 00:26:23,949 --> 00:26:26,850
2247 | Now color can also be too bright, distracting, and
2248 |
2249 | 562
2250 | 00:26:26,919 --> 00:26:28,585
2251 | contrast and transparency and
2252 |
2253 | 563
2254 | 00:26:28,653 --> 00:26:32,222
2255 | blurring can all have negative impacts on legibility for
2256 |
2257 | 564
2258 | 00:26:32,291 --> 00:26:34,891
2259 | people that have certain vision conditions.
2260 |
2261 | 565
2262 | 00:26:34,960 --> 00:26:37,427
2263 | This is the default control center on iOS and
2264 |
2265 | 566
2266 | 00:26:37,496 --> 00:26:40,330
2267 | as you can see color bleeds through from behind and
2268 |
2269 | 567
2270 | 00:26:40,399 --> 00:26:43,233
2271 | is blurred by the control center's background.
2272 |
2273 | 568
2274 | 00:26:43,302 --> 00:26:45,402
2275 | But if I turn on the darken colors and
2276 |
2277 | 569
2278 | 00:26:45,471 --> 00:26:47,370
2279 | reduce transparency setting,
2280 |
2281 | 570
2282 | 00:26:47,439 --> 00:26:51,941
2283 | we no longer get those colors bleeding through from behind.
2284 |
2285 | 571
2286 | 00:26:52,010 --> 00:26:53,777
2287 | And the contrast between the colors and
2288 |
2289 | 572
2290 | 00:26:53,846 --> 00:26:55,846
2291 | the lighter background is much more stark,
2292 |
2293 | 573
2294 | 00:26:55,914 --> 00:26:58,482
2295 | which means that it's a lot more readable to those users
2296 |
2297 | 574
2298 | 00:26:58,550 --> 00:27:00,850
2299 | that have those vision conditions.
2300 |
2301 | 575
2302 | 00:27:00,919 --> 00:27:03,854
2303 | So you can check whether things like these are enabled
2304 |
2305 | 576
2306 | 00:27:03,922 --> 00:27:06,523
2307 | through these two UIKit functions.
2308 |
2309 | 577
2310 | 00:27:06,591 --> 00:27:09,693
2311 | And this way, you can adapt your interface to the needs
2312 |
2313 | 578
2314 | 00:27:09,761 --> 00:27:12,496
2315 | of your users rather than having to try and create
2316 |
2317 | 579
2318 | 00:27:12,564 --> 00:27:16,066
2319 | some design that, from the get go, applies to everybody.
2320 |
2321 | 580
2322 | 00:27:18,503 --> 00:27:21,071
2323 | Now for this next one, I'm going to say that anybody in
2324 |
2325 | 581
2326 | 00:27:21,140 --> 00:27:23,840
2327 | the room who gets motion sick from phone animation should
2328 |
2329 | 582
2330 | 00:27:23,909 --> 00:27:26,042
2331 | probably look away for a second.
2332 |
2333 | 583
2334 | 00:27:26,111 --> 00:27:27,911
2335 | Device is gonna show these standard
2336 |
2337 | 584
2338 | 00:27:27,979 --> 00:27:30,047
2339 | app opening animation.
2340 |
2341 | 585
2342 | 00:27:30,116 --> 00:27:32,282
2343 | So you can see that when I tap on music,
2344 |
2345 | 586
2346 | 00:27:32,351 --> 00:27:34,884
2347 | the app expands from its place on the dock, and
2348 |
2349 | 587
2350 | 00:27:34,953 --> 00:27:38,154
2351 | the screen swoops in to center on it.
2352 |
2353 | 588
2354 | 00:27:38,223 --> 00:27:40,623
2355 | But if I turn on the reduce motion setting,
2356 |
2357 | 589
2358 | 00:27:40,692 --> 00:27:43,193
2359 | I instead get this cross fade.
2360 |
2361 | 590
2362 | 00:27:43,262 --> 00:27:46,864
2363 | So there are certain people with vestibular disorders
2364 |
2365 | 591
2366 | 00:27:46,932 --> 00:27:50,934
2367 | that can be triggered by complex motion which most
2368 |
2369 | 592
2370 | 00:27:51,002 --> 00:27:54,271
2371 | often results in things like nausea and dizziness.
2372 |
2373 | 593
2374 | 00:27:54,339 --> 00:27:57,407
2375 | So you should be mindful of any animations in your app,
2376 |
2377 | 594
2378 | 00:27:57,476 --> 00:28:00,544
2379 | particularly if they cause a lot of movement or
2380 |
2381 | 595
2382 | 00:28:00,613 --> 00:28:03,113
2383 | are unexpected in some way.
2384 |
2385 | 596
2386 | 00:28:03,181 --> 00:28:05,715
2387 | You should consider enabling an alternative
2388 |
2389 | 597
2390 | 00:28:05,784 --> 00:28:08,852
2391 | animation when this setting is enabled which you can check
2392 |
2393 | 598
2394 | 00:28:08,920 --> 00:28:09,953
2395 | through a similar UIKit function.
2396 |
2397 | 599
2398 | 00:28:12,724 --> 00:28:14,391
2399 | Now the final visual accommodation that I'd like
2400 |
2401 | 600
2402 | 00:28:14,460 --> 00:28:17,594
2403 | to talk about today relates to typography, and
2404 |
2405 | 601
2406 | 00:28:17,663 --> 00:28:20,430
2407 | it's dynamic type which is a feature in iOS that allows
2408 |
2409 | 602
2410 | 00:28:20,499 --> 00:28:22,299
2411 | a user to scale their font.
2412 |
2413 | 603
2414 | 00:28:22,368 --> 00:28:24,535
2415 | And I believe you touched on it very briefly.
2416 |
2417 | 604
2418 | 00:28:26,138 --> 00:28:29,339
2419 | There are many users out there who struggle to use devices
2420 |
2421 | 605
2422 | 00:28:29,407 --> 00:28:32,442
2423 | because the type is so small, or so thin that it ends up
2424 |
2425 | 606
2426 | 00:28:32,511 --> 00:28:35,111
2427 | blurring together, and they can't read it.
2428 |
2429 | 607
2430 | 00:28:35,180 --> 00:28:38,582
2431 | And this applies to people with low vision conditions,
2432 |
2433 | 608
2434 | 00:28:38,651 --> 00:28:41,718
2435 | but it also applies to people whose vision is simply
2436 |
2437 | 609
2438 | 00:28:41,787 --> 00:28:43,420
2439 | deteriorated from age, or
2440 |
2441 | 610
2442 | 00:28:43,489 --> 00:28:46,223
2443 | people who simply need to wear glasses.
2444 |
2445 | 611
2446 | 00:28:46,292 --> 00:28:48,925
2447 | So, Dynamic Type is meant to help adapt these
2448 |
2449 | 612
2450 | 00:28:48,994 --> 00:28:50,327
2451 | people's devices to their needs.
2452 |
2453 | 613
2454 | 00:28:50,396 --> 00:28:54,865
2455 | Now on the left you see the standard Mail inbox interface
2456 |
2457 | 614
2458 | 00:28:54,933 --> 00:28:55,599
2459 | with the default text.
2460 |
2461 | 615
2462 | 00:28:55,667 --> 00:28:58,968
2463 | And on the right I've scaled it up several levels.
2464 |
2465 | 616
2466 | 00:28:59,037 --> 00:28:59,836
2467 | And as you can see,
2468 |
2469 | 617
2470 | 00:28:59,904 --> 00:29:02,372
2471 | the interface has adapted itself and the layout as well
2472 |
2473 | 618
2474 | 00:29:02,441 --> 00:29:05,341
2475 | to accommodate the larger text size.
2476 |
2477 | 619
2478 | 00:29:05,410 --> 00:29:07,811
2479 | The most common way that you're gonna get this behavior
2480 |
2481 | 620
2482 | 00:29:07,880 --> 00:29:11,882
2483 | is by using this method preferredFont(forTextStyle.
2484 |
2485 | 621
2486 | 00:29:11,950 --> 00:29:13,751
2487 | which is a class method on UIFont.
2488 |
2489 | 622
2490 | 00:29:14,986 --> 00:29:17,220
2491 | When you set the font of a UILabel or
2492 |
2493 | 623
2494 | 00:29:17,288 --> 00:29:20,958
2495 | UITextView, using this method, the font will be scaled to
2496 |
2497 | 624
2498 | 00:29:21,026 --> 00:29:24,060
2499 | the user's preference using the system font.
2500 |
2501 | 625
2502 | 00:29:24,129 --> 00:29:26,730
2503 | And what you do is you pass through a TextStyle, which
2504 |
2505 | 626
2506 | 00:29:26,798 --> 00:29:29,565
2507 | indicates what the general purpose of the text is.
2508 |
2509 | 627
2510 | 00:29:29,634 --> 00:29:33,036
2511 | So titles are large and body is a more standard size.
2512 |
2513 | 628
2514 | 00:29:33,105 --> 00:29:36,073
2515 | There are these eight distinct styles that you can pass this
2516 |
2517 | 629
2518 | 00:29:36,141 --> 00:29:39,009
2519 | method and each of them have pre-defined point sizes and
2520 |
2521 | 630
2522 | 00:29:39,077 --> 00:29:40,310
2523 | weight sizes to them.
2524 |
2525 | 631
2526 | 00:29:42,414 --> 00:29:45,215
2527 | So, let's look at some code where I used that.
2528 |
2529 | 632
2530 | 00:29:45,284 --> 00:29:48,118
2531 | So let's say I have MyLabelView which is
2532 |
2533 | 633
2534 | 00:29:48,187 --> 00:29:50,987
2535 | a custom UIView, and it has a sub label or
2536 |
2537 | 634
2538 | 00:29:51,056 --> 00:29:53,556
2539 | a sub view that is of class UILabel.
2540 |
2541 | 635
2542 | 00:29:53,625 --> 00:29:56,293
2543 | Now in my init method, I'm going to init that label.
2544 |
2545 | 636
2546 | 00:29:56,362 --> 00:29:58,828
2547 | Now, I'm gonna set its number of lines to be 0.
2548 |
2549 | 637
2550 | 00:29:58,897 --> 00:30:02,232
2551 | And what this indicates to the UILabel, is that it doesn't
2552 |
2553 | 638
2554 | 00:30:02,301 --> 00:30:05,201
2555 | need to be limited to any specific number of lines.
2556 |
2557 | 639
2558 | 00:30:05,270 --> 00:30:07,570
2559 | It can actually grow to an unbounded number of lines.
2560 |
2561 | 640
2562 | 00:30:07,639 --> 00:30:10,440
2563 | Which is important when I'm growing the text size because
2564 |
2565 | 641
2566 | 00:30:10,508 --> 00:30:13,376
2567 | as I get bigger and bigger, it's likelier, it's more and
2568 |
2569 | 642
2570 | 00:30:13,445 --> 00:30:16,012
2571 | more likely that I'm not gonna be able to fit whatever
2572 |
2573 | 643
2574 | 00:30:16,081 --> 00:30:17,581
2575 | text I have on a single line.
2576 |
2577 | 644
2578 | 00:30:19,985 --> 00:30:23,720
2579 | Now I also need to set adjustsFontForContentSizeCate-
2580 |
2581 | 645
2582 | 00:30:23,788 --> 00:30:27,524
2583 | gory to be true, and what this does is it tells the label
2584 |
2585 | 646
2586 | 00:30:27,592 --> 00:30:30,927
2587 | that when the user has changed their font size and
2588 |
2589 | 647
2590 | 00:30:30,996 --> 00:30:35,565
2591 | my app is opened in the background, I need to update.
2592 |
2593 | 648
2594 | 00:30:35,633 --> 00:30:38,569
2595 | The label needs to update itself to match whatever
2596 |
2597 | 649
2598 | 00:30:38,637 --> 00:30:41,872
2599 | the new font that I've changed my size to is.
2600 |
2601 | 650
2602 | 00:30:43,842 --> 00:30:46,009
2603 | And then I am going to use that preferredFont
2604 |
2605 | 651
2606 | 00:30:46,078 --> 00:30:46,843
2607 | forTextStyle.
2608 |
2609 | 652
2610 | 00:30:46,912 --> 00:30:48,744
2611 | Probably just gonna use body,
2612 |
2613 | 653
2614 | 00:30:48,813 --> 00:30:52,482
2615 | because it's standard in this case and then add my subview.
2616 |
2617 | 654
2618 | 00:30:52,550 --> 00:30:55,485
2619 | Now, what do you do in the case where you wanna use
2620 |
2621 | 655
2622 | 00:30:55,554 --> 00:30:58,355
2623 | a custom point size when you're at the default
2624 |
2625 | 656
2626 | 00:30:58,423 --> 00:30:59,156
2627 | text size?
2628 |
2629 | 657
2630 | 00:30:59,225 --> 00:31:01,457
2631 | Or you even wanna use a custom font but
2632 |
2633 | 658
2634 | 00:31:01,526 --> 00:31:02,926
2635 | you still wanna support dynamic type.
2636 |
2637 | 659
2638 | 00:31:04,229 --> 00:31:05,762
2639 | I did this in my own sample app,
2640 |
2641 | 660
2642 | 00:31:05,831 --> 00:31:08,097
2643 | it uses the boldSystemFontOfSize method,
2644 |
2645 | 661
2646 | 00:31:08,166 --> 00:31:10,600
2647 | which is not going to automatically be scaled to
2648 |
2649 | 662
2650 | 00:31:10,668 --> 00:31:12,135
2651 | the user's preference.
2652 |
2653 | 663
2654 | 00:31:13,705 --> 00:31:16,973
2655 | So, what I'm gonna do is I'm going to take advantage of
2656 |
2657 | 664
2658 | 00:31:17,042 --> 00:31:21,879
2659 | this property on UIApplication preferredContestSizeCategory.
2660 |
2661 | 665
2662 | 00:31:22,848 --> 00:31:24,113
2663 | And what this tells me,
2664 |
2665 | 666
2666 | 00:31:24,182 --> 00:31:26,450
2667 | is what the user has currently set their font to.
2668 |
2669 | 667
2670 | 00:31:28,653 --> 00:31:35,124
2671 | Now there are seven distinct size categories at default.
2672 |
2673 | 668
2674 | 00:31:35,193 --> 00:31:37,661
2675 | The large size is the default size on iOS.
2676 |
2677 | 669
2678 | 00:31:39,031 --> 00:31:42,899
2679 | But there are also five more accessibility sizes and
2680 |
2681 | 670
2682 | 00:31:42,968 --> 00:31:46,536
2683 | located in accessibility settings that can make
2684 |
2685 | 671
2686 | 00:31:46,605 --> 00:31:48,872
2687 | the text really, really big.
2688 |
2689 | 672
2690 | 00:31:48,940 --> 00:31:52,409
2691 | So what would my code for something like this look like?
2692 |
2693 | 673
2694 | 00:31:52,478 --> 00:31:56,045
2695 | Well, I'd probably create some sort of NSObject like
2696 |
2697 | 674
2698 | 00:31:56,114 --> 00:31:59,248
2699 | MyFontManager, that will be an object that will manage all
2700 |
2701 | 675
2702 | 00:31:59,317 --> 00:32:02,219
2703 | the fonts for my app so that I can run everything through it.
2704 |
2705 | 676
2706 | 00:32:03,656 --> 00:32:06,289
2707 | And then I'd have some method like this,
2708 |
2709 | 677
2710 | 00:32:06,358 --> 00:32:10,927
2711 | where I'd use a fontSize variable and write a switch
2712 |
2713 | 678
2714 | 00:32:10,996 --> 00:32:14,197
2715 | statement that changes the value of the fontSize based
2716 |
2717 | 679
2718 | 00:32:14,266 --> 00:32:17,734
2719 | on what my sizeCategory is set to, to some sensible value.
2720 |
2721 | 680
2722 | 00:32:17,802 --> 00:32:20,303
2723 | I mean to do that for every case.
2724 |
2725 | 681
2726 | 00:32:20,372 --> 00:32:22,605
2727 | And then I'm gonna use whatever the method
2728 |
2729 | 682
2730 | 00:32:22,674 --> 00:32:25,375
2731 | I was going to use before, like systemFont(ofSize: or
2732 |
2733 | 683
2734 | 00:32:25,444 --> 00:32:28,445
2735 | my custom font or boldSystemFont(ofSize:
2736 |
2737 | 684
2738 | 00:32:28,514 --> 00:32:31,281
2739 | using whatever size I determined was appropriate for
2740 |
2741 | 685
2742 | 00:32:31,350 --> 00:32:32,482
2743 | the current size class.
2744 |
2745 | 686
2746 | 00:32:34,252 --> 00:32:39,556
2747 | Now it's also important that I register myself to listen for
2748 |
2749 | 687
2750 | 00:32:39,624 --> 00:32:42,125
2751 | the UIContentSizeCategoryDidChange
2752 |
2753 | 688
2754 | 00:32:42,194 --> 00:32:42,992
2755 | notification.
2756 |
2757 | 689
2758 | 00:32:43,061 --> 00:32:45,428
2759 | Because I'm no longer using that preferred font for
2760 |
2761 | 690
2762 | 00:32:45,496 --> 00:32:48,831
2763 | text style method so all my views aren't gonna know that
2764 |
2765 | 691
2766 | 00:32:48,900 --> 00:32:51,968
2767 | they need to update themselves when the font size changes.
2768 |
2769 | 692
2770 | 00:32:52,036 --> 00:32:55,372
2771 | So I'm gonna register myself as an observer on this
2772 |
2773 | 693
2774 | 00:32:55,440 --> 00:32:59,408
2775 | notification and just write a method that updates
2776 |
2777 | 694
2778 | 00:32:59,477 --> 00:33:01,078
2779 | my fonts in some sort of sensible way.
2780 |
2781 | 695
2782 | 00:33:02,814 --> 00:33:05,749
2783 | So let's move for the final time to my demo app,
2784 |
2785 | 696
2786 | 00:33:05,818 --> 00:33:08,185
2787 | and see what it's like with dynamic type.
2788 |
2789 | 697
2790 | 00:33:10,088 --> 00:33:13,090
2791 | Now for this, I'm actually gonna exit full screen.
2792 |
2793 | 698
2794 | 00:33:17,162 --> 00:33:21,698
2795 | And I'm going to bring up this tool in Xcode called
2796 |
2797 | 699
2798 | 00:33:21,767 --> 00:33:24,668
2799 | the Accessibility Inspector.
2800 |
2801 | 700
2802 | 00:33:24,736 --> 00:33:27,870
2803 | Now this is a super useful tool that I don't really have
2804 |
2805 | 701
2806 | 00:33:27,939 --> 00:33:31,040
2807 | time to go in to today about how you can use it.
2808 |
2809 | 702
2810 | 00:33:31,109 --> 00:33:34,477
2811 | But, it's an app that's built into Xcode that allows you to
2812 |
2813 | 703
2814 | 00:33:34,546 --> 00:33:36,213
2815 | audit your own application for
2816 |
2817 | 704
2818 | 00:33:36,281 --> 00:33:38,314
2819 | all of its accessibility problems.
2820 |
2821 | 705
2822 | 00:33:38,383 --> 00:33:41,284
2823 | And there's a great video from last year's WWDC that you can
2824 |
2825 | 706
2826 | 00:33:41,353 --> 00:33:43,787
2827 | find on the developer website to go through exactly
2828 |
2829 | 707
2830 | 00:33:43,855 --> 00:33:44,887
2831 | how you used this app,
2832 |
2833 | 708
2834 | 00:33:44,956 --> 00:33:48,558
2835 | which I will have a link to at the end of the presentation.
2836 |
2837 | 709
2838 | 00:33:48,627 --> 00:33:51,427
2839 | But for now, I'm going to attach to my phone and
2840 |
2841 | 710
2842 | 00:33:51,496 --> 00:33:54,531
2843 | simply use it to change the font size dynamically so
2844 |
2845 | 711
2846 | 00:33:54,599 --> 00:33:57,867
2847 | that you can see what happens on the screen, what I do.
2848 |
2849 | 712
2850 | 00:33:57,936 --> 00:34:00,704
2851 | So I'm gonna come to my stack of cards, and
2852 |
2853 | 713
2854 | 00:34:00,773 --> 00:34:04,374
2855 | I can see that the number of
2856 |
2857 | 714
2858 | 00:34:04,443 --> 00:34:08,144
2859 | lines is already set to zero because this label is growing
2860 |
2861 | 715
2862 | 00:34:08,213 --> 00:34:11,380
2863 | based on how much text I have there as I want it to.
2864 |
2865 | 716
2866 | 00:34:11,449 --> 00:34:12,748
2867 | But we're gonna see,
2868 |
2869 | 717
2870 | 00:34:12,817 --> 00:34:15,518
2871 | is as I change this value here with the slider,
2872 |
2873 | 718
2874 | 00:34:15,587 --> 00:34:18,622
2875 | my text isn't updating at all, the content size.
2876 |
2877 | 719
2878 | 00:34:18,690 --> 00:34:19,723
2879 | So something is wrong.
2880 |
2881 | 720
2882 | 00:34:20,892 --> 00:34:24,194
2883 | So I'm gonna come over here to MyFontManager.
2884 |
2885 | 721
2886 | 00:34:28,066 --> 00:34:29,832
2887 | And I'm gonna go look at my appFont method and
2888 |
2889 | 722
2890 | 00:34:29,901 --> 00:34:31,468
2891 | I see the problem immediately.
2892 |
2893 | 723
2894 | 00:34:31,536 --> 00:34:34,504
2895 | I'm not adapting myself to what the preferred contentSize
2896 |
2897 | 724
2898 | 00:34:34,573 --> 00:34:36,673
2899 | is and I'm not using the preferred font for
2900 |
2901 | 725
2902 | 00:34:36,742 --> 00:34:37,841
2903 | text style method.
2904 |
2905 | 726
2906 | 00:34:46,785 --> 00:34:51,420
2907 | So I'm gonna replace that, With this,
2908 |
2909 | 727
2910 | 00:34:51,489 --> 00:34:53,456
2911 | which takes this size and,
2912 |
2913 | 728
2914 | 00:34:53,524 --> 00:34:57,827
2915 | based on some multiplier that I decided looks good.
2916 |
2917 | 729
2918 | 00:34:57,896 --> 00:35:00,696
2919 | I'm going to modify what the font size is,
2920 |
2921 | 730
2922 | 00:35:00,765 --> 00:35:02,632
2923 | based on the SizeCategory.
2924 |
2925 | 731
2926 | 00:35:02,701 --> 00:35:04,534
2927 | And I'm going to return that using my
2928 |
2929 | 732
2930 | 00:35:04,603 --> 00:35:06,135
2931 | boldSystemFont(ofSize:.
2932 |
2933 | 733
2934 | 00:35:06,204 --> 00:35:07,204
2935 | Now, like I said,
2936 |
2937 | 734
2938 | 00:35:07,272 --> 00:35:09,940
2939 | I also need to register for that notification, so
2940 |
2941 | 735
2942 | 00:35:10,008 --> 00:35:12,775
2943 | that my view actually updates itself in real time.
2944 |
2945 | 736
2946 | 00:35:12,844 --> 00:35:14,177
2947 | So we're gonna go to that cell.
2948 |
2949 | 737
2950 | 00:35:16,448 --> 00:35:19,849
2951 | And I'm going to add myself as an observer,
2952 |
2953 | 738
2954 | 00:35:19,917 --> 00:35:21,785
2955 | not to put that there.
2956 |
2957 | 739
2958 | 00:35:27,426 --> 00:35:29,325
2959 | And in my contentSizeCategoryChange
2960 |
2961 | 740
2962 | 00:35:29,394 --> 00:35:32,129
2963 | method, I'm just going to update the fonts here.
2964 |
2965 | 741
2966 | 00:35:37,235 --> 00:35:39,136
2967 | And that should work, hopefully, so let's rebuild.
2968 |
2969 | 742
2970 | 00:35:41,172 --> 00:35:42,405
2971 | So I'm gonna come back over here.
2972 |
2973 | 743
2974 | 00:35:44,309 --> 00:35:45,808
2975 | I'm gonna open this and
2976 |
2977 | 744
2978 | 00:35:45,877 --> 00:35:49,545
2979 | I'm gonna bring up my Accessibility Inspector again.
2980 |
2981 | 745
2982 | 00:35:49,614 --> 00:35:52,849
2983 | And now as I change the size you see that it's growing
2984 |
2985 | 746
2986 | 00:35:52,918 --> 00:35:57,486
2987 | bigger, and bigger, until it's real, real big.
2988 |
2989 | 747
2990 | 00:35:57,555 --> 00:36:00,223
2991 | And everything works exactly as I was expecting it to.
2992 |
2993 | 748
2994 | 00:36:00,292 --> 00:36:02,759
2995 | And, not a huge change.
2996 |
2997 | 749
2998 | 00:36:02,828 --> 00:36:07,630
2999 | So, I've covered several ways that you as a develop,
3000 |
3001 | 750
3002 | 00:36:07,699 --> 00:36:11,901
3003 | developer can make your app more accessible to people.
3004 |
3005 | 751
3006 | 00:36:11,969 --> 00:36:14,937
3007 | This can actually be a great way to get your app featured
3008 |
3009 | 752
3010 | 00:36:15,006 --> 00:36:15,872
3011 | on the store.
3012 |
3013 | 753
3014 | 00:36:15,941 --> 00:36:18,608
3015 | So we have sections that are devoted specifically to
3016 |
3017 | 754
3018 | 00:36:18,677 --> 00:36:20,409
3019 | general purpose applications.
3020 |
3021 | 755
3022 | 00:36:20,478 --> 00:36:21,344
3023 | That we think we've done
3024 |
3025 | 756
3026 | 00:36:21,413 --> 00:36:23,212
3027 | a good job with their accessibility.
3028 |
3029 | 757
3030 | 00:36:23,281 --> 00:36:25,715
3031 | For instance, this collection of apps that
3032 |
3033 | 758
3034 | 00:36:25,784 --> 00:36:28,117
3035 | are good to use with VoiceOver.
3036 |
3037 | 759
3038 | 00:36:28,186 --> 00:36:31,554
3039 | Beyond making your own app accessible,
3040 |
3041 | 760
3042 | 00:36:31,622 --> 00:36:35,691
3043 | there's also a whole set of apps that are aimed at
3044 |
3045 | 761
3046 | 00:36:35,760 --> 00:36:38,628
3047 | accessible users specifically.
3048 |
3049 | 762
3050 | 00:36:38,696 --> 00:36:41,665
3051 | So, I'd like to run through a few of those examples with
3052 |
3053 | 763
3054 | 00:36:41,733 --> 00:36:43,299
3055 | you today.
3056 |
3057 | 764
3058 | 00:36:43,368 --> 00:36:47,237
3059 | We have knfbReader, which is an app that scans
3060 |
3061 | 765
3062 | 00:36:47,305 --> 00:36:50,507
3063 | text in real time, and let's users who are low vision or
3064 |
3065 | 766
3066 | 00:36:50,576 --> 00:36:52,975
3067 | blind interact with things like paper or
3068 |
3069 | 767
3070 | 00:36:53,044 --> 00:36:54,811
3071 | a restaurant menu, so they can read it.
3072 |
3073 | 768
3074 | 00:36:56,348 --> 00:36:59,783
3075 | We have an app like Ava, which transcribes conversations in
3076 |
3077 | 769
3078 | 00:36:59,851 --> 00:37:02,686
3079 | real time, so that a user who's hard of hearing or
3080 |
3081 | 770
3082 | 00:37:02,754 --> 00:37:05,454
3083 | even deaf, can follow a conversation easier.
3084 |
3085 | 771
3086 | 00:37:05,523 --> 00:37:08,024
3087 | And this includes a feature that actually breaks
3088 |
3089 | 772
3090 | 00:37:08,093 --> 00:37:10,860
3091 | conversation down, differentiating the different
3092 |
3093 | 773
3094 | 00:37:10,929 --> 00:37:13,530
3095 | speakers by color so I can tell who is speaking.
3096 |
3097 | 774
3098 | 00:37:15,300 --> 00:37:18,034
3099 | And finally we have this app, Children with Autism,
3100 |
3101 | 775
3102 | 00:37:18,102 --> 00:37:20,537
3103 | which is a visual scheduler built specifically for
3104 |
3105 | 776
3106 | 00:37:20,605 --> 00:37:22,471
3107 | children with autism.
3108 |
3109 | 777
3110 | 00:37:22,540 --> 00:37:25,374
3111 | And allows them to be more independent and
3112 |
3113 | 778
3114 | 00:37:25,443 --> 00:37:27,676
3115 | understand what they need to do,
3116 |
3117 | 779
3118 | 00:37:27,745 --> 00:37:31,548
3119 | during their day as they are going along, task by task.
3120 |
3121 | 780
3122 | 00:37:31,617 --> 00:37:34,283
3123 | So these are just a couple of examples.
3124 |
3125 | 781
3126 | 00:37:34,352 --> 00:37:37,686
3127 | And you may wonder, why am I telling you about this?
3128 |
3129 | 782
3130 | 00:37:37,755 --> 00:37:42,425
3131 | Well, basically, if you're looking for a possible idea
3132 |
3133 | 783
3134 | 00:37:42,494 --> 00:37:44,994
3135 | for a class of what you might want to work on.
3136 |
3137 | 784
3138 | 00:37:45,062 --> 00:37:48,231
3139 | Or the next great thing that you think you wanna work on,
3140 |
3141 | 785
3142 | 00:37:48,300 --> 00:37:51,534
3143 | I encourage you to check out some of the work that's being
3144 |
3145 | 786
3146 | 00:37:51,603 --> 00:37:54,837
3147 | done in accessibility because there are a lot of problems
3148 |
3149 | 787
3150 | 00:37:54,906 --> 00:37:58,575
3151 | that still aren't solved, and that are worthwhile to tackle.
3152 |
3153 | 788
3154 | 00:37:58,643 --> 00:38:00,476
3155 | Now, I've covered a lot today and
3156 |
3157 | 789
3158 | 00:38:00,545 --> 00:38:03,379
3159 | there's more that you can find on the web.
3160 |
3161 | 790
3162 | 00:38:03,448 --> 00:38:06,682
3163 | These are a couple of links to some resources that you might
3164 |
3165 | 791
3166 | 00:38:06,751 --> 00:38:09,318
3167 | find useful, including some of the things that I spoke about
3168 |
3169 | 792
3170 | 00:38:09,387 --> 00:38:10,720
3171 | during the presentation today.
3172 |
3173 | 793
3174 | 00:38:12,390 --> 00:38:14,324
3175 | I would encourage you to check out some of these WWDC videos,
3176 |
3177 | 794
3178 | 00:38:14,325 --> 00:38:16,259
3179 | In particular,
3180 |
3181 | 795
3182 | 00:38:16,328 --> 00:38:18,628
3183 | including the one on inclusive app design,
3184 |
3185 | 796
3186 | 00:38:18,697 --> 00:38:21,531
3187 | which is a whole session on design, focused on
3188 |
3189 | 797
3190 | 00:38:21,599 --> 00:38:24,734
3191 | both accessibility as well as internationalization.
3192 |
3193 | 798
3194 | 00:38:24,803 --> 00:38:26,869
3195 | And that auditing your apps for accessibility,
3196 |
3197 | 799
3198 | 00:38:26,938 --> 00:38:29,572
3199 | which goes through how to take advantage of the accessibility
3200 |
3201 | 800
3202 | 00:38:29,641 --> 00:38:31,708
3203 | inspector to make your own apps accessible.
3204 |
3205 | 801
3206 | 00:38:34,545 --> 00:38:35,645
3207 | So, in closing,
3208 |
3209 | 802
3210 | 00:38:35,714 --> 00:38:39,081
3211 | I'd like to circle back to the why of it all.
3212 |
3213 | 803
3214 | 00:38:39,150 --> 00:38:42,885
3215 | Why should you take the time to do something like this?
3216 |
3217 | 804
3218 | 00:38:42,954 --> 00:38:46,055
3219 | Let me read you this quote from Sady, the woman who,
3220 |
3221 | 805
3222 | 00:38:46,124 --> 00:38:49,492
3223 | from the video that I showed at the beginning.
3224 |
3225 | 806
3226 | 00:38:49,561 --> 00:38:52,428
3227 | My love for technology is more than just a passion.
3228 |
3229 | 807
3230 | 00:38:52,497 --> 00:38:54,831
3231 | It gives me access to my world.
3232 |
3233 | 808
3234 | 00:38:54,899 --> 00:38:57,634
3235 | I need help in some areas, but assistive technology
3236 |
3237 | 809
3238 | 00:38:57,702 --> 00:39:00,069
3239 | enables me to communicate with my loved ones, and
3240 |
3241 | 810
3242 | 00:39:00,138 --> 00:39:01,771
3243 | pursue my career.
3244 |
3245 | 811
3246 | 00:39:01,840 --> 00:39:03,572
3247 | What everybody else can do with a keyboard and
3248 |
3249 | 812
3250 | 00:39:03,641 --> 00:39:06,009
3251 | a mouse, I can do with my two switches.
3252 |
3253 | 813
3254 | 00:39:08,012 --> 00:39:11,981
3255 | The common person's life is enhanced by technology.
3256 |
3257 | 814
3258 | 00:39:12,050 --> 00:39:15,318
3259 | But for somebody like Sady, technology is transformative.
3260 |
3261 | 815
3262 | 00:39:16,721 --> 00:39:19,455
3263 | It can make them independent in ways that really couldn't
3264 |
3265 | 816
3266 | 00:39:19,524 --> 00:39:22,024
3267 | have been imagined ten years ago.
3268 |
3269 | 817
3270 | 00:39:22,093 --> 00:39:24,894
3271 | It can allow them to do jobs that they couldn't have done,
3272 |
3273 | 818
3274 | 00:39:24,962 --> 00:39:27,163
3275 | have hobbies that they couldn't have had, or
3276 |
3277 | 819
3278 | 00:39:27,232 --> 00:39:29,866
3279 | experience the world in ways that they couldn't have.
3280 |
3281 | 820
3282 | 00:39:31,569 --> 00:39:34,303
3283 | So by taking the time and putting in the effort to make
3284 |
3285 | 821
3286 | 00:39:34,372 --> 00:39:37,039
3287 | sure that the work you do works for everyone, you can
3288 |
3289 | 822
3290 | 00:39:37,108 --> 00:39:41,110
3291 | have a lasting, meaningful impact on people's lives.
3292 |
3293 | 823
3294 | 00:39:41,178 --> 00:39:43,546
3295 | I promise you that you'll never find a more loyal
3296 |
3297 | 824
3298 | 00:39:43,614 --> 00:39:46,783
3299 | customer than the one whose life you made better.
3300 |
3301 | 825
3302 | 00:39:46,851 --> 00:39:48,485
3303 | Now I know that some of you may be thinking that that's
3304 |
3305 | 826
3306 | 00:39:48,553 --> 00:39:50,686
3307 | great and all, but there are some things that
3308 |
3309 | 827
3310 | 00:39:50,755 --> 00:39:53,956
3311 | really just don't work with accessibility.
3312 |
3313 | 828
3314 | 00:39:54,025 --> 00:39:55,692
3315 | And I challenge you to think different.
3316 |
3317 | 829
3318 | 00:39:57,261 --> 00:40:00,095
3319 | If you'd asked somebody 15 years ago how a blind person
3320 |
3321 | 830
3322 | 00:40:00,164 --> 00:40:00,930
3323 | could use a touch screen,
3324 |
3325 | 831
3326 | 00:40:00,999 --> 00:40:03,465
3327 | they probably would have told you that they couldn't.
3328 |
3329 | 832
3330 | 00:40:03,534 --> 00:40:04,534
3331 | And that's not true today.
3332 |
3333 | 833
3334 | 00:40:06,137 --> 00:40:09,906
3335 | Anything is really possible when you put your mind to it.
3336 |
3337 | 834
3338 | 00:40:09,975 --> 00:40:13,476
3339 | So this is a video of my colleague Ryan DJing at last
3340 |
3341 | 835
3342 | 00:40:13,545 --> 00:40:14,610
3343 | year's WWDC.
3344 |
3345 | 836
3346 | 00:40:14,679 --> 00:40:16,412
3347 | Where we awarded the app djay Pro for
3348 |
3349 | 837
3350 | 00:40:16,481 --> 00:40:19,148
3351 | their work on accessibility.
3352 |
3353 | 838
3354 | 00:40:19,217 --> 00:40:22,018
3355 | He DJed live on stage using the app with VoiceOver and
3356 |
3357 | 839
3358 | 00:40:22,087 --> 00:40:24,386
3359 | I'd like to play this brief clip for you now.
3360 |
3361 | 840
3362 | 00:40:24,455 --> 00:40:26,789
3363 | I have an iPad Pro running djay Pro and
3364 |
3365 | 841
3366 | 00:40:26,858 --> 00:40:28,324
3367 | this external mixer.
3368 |
3369 | 842
3370 | 00:40:28,392 --> 00:40:31,494
3371 | I'm gonna go ahead and throw on my headphones now.
3372 |
3373 | 843
3374 | 00:40:31,562 --> 00:40:35,598
3375 | So, here's the things that's interesting, the external DJ
3376 |
3377 | 844
3378 | 00:40:35,667 --> 00:40:39,001
3379 | controller acts as an extension of the onscreen UI.
3380 |
3381 | 845
3382 | 00:40:39,070 --> 00:40:42,104
3383 | And so I can use it to really create kind of a pretty
3384 |
3385 | 846
3386 | 00:40:42,173 --> 00:40:43,505
3387 | cool performance.
3388 |
3389 | 847
3390 | 00:40:43,574 --> 00:40:45,575
3391 | Also you're probably wondering what of this can I see.
3392 |
3393 | 848
3394 | 00:40:46,911 --> 00:40:47,743
3395 | Not much.
3396 |
3397 | 849
3398 | 00:40:47,812 --> 00:40:50,112
3399 | I pretty can see the light coming from the screen and
3400 |
3401 | 850
3402 | 00:40:50,181 --> 00:40:52,848
3403 | some of the colorful lights coming from the DJ controller,
3404 |
3405 | 851
3406 | 00:40:52,917 --> 00:40:54,417
3407 | but that's about it.
3408 |
3409 | 852
3410 | 00:40:54,485 --> 00:40:55,518
3411 | So knowing that,
3412 |
3413 | 853
3414 | 00:40:55,587 --> 00:40:58,154
3415 | we're gonna use VoiceOver to control this interface.
3416 |
3417 | 854
3418 | 00:40:58,223 --> 00:40:59,455
3419 | Let's go ahead and get the music started.
3420 |
3421 | 855
3422 | 00:40:59,524 --> 00:41:05,862
3423 | Play Okay, so the first thing I'd like to point out is that
3424 |
3425 | 856
3426 | 00:41:05,930 --> 00:41:08,598
3427 | I have access to information I've never had before.
3428 |
3429 | 857
3430 | 00:41:08,666 --> 00:41:10,132
3431 | For example, the time.
3432 |
3433 | 858
3434 | 00:41:10,201 --> 00:41:11,501
3435 | How much time is left on this track?
3436 |
3437 | 859
3438 | 00:41:11,569 --> 00:41:12,134
3439 | Let's find out.
3440 |
3441 | 860
3442 | 00:41:12,203 --> 00:41:14,804
3443 | Time deck one, 2:56.
3444 |
3445 | 861
3446 | 00:41:14,872 --> 00:41:15,471
3447 | That's perfect.
3448 |
3449 | 862
3450 | 00:41:15,540 --> 00:41:16,539
3451 | Okay, so I'm the DJ.
3452 |
3453 | 863
3454 | 00:41:16,608 --> 00:41:17,873
3455 | I'm supposed to keep the music going, and
3456 |
3457 | 864
3458 | 00:41:17,942 --> 00:41:19,642
3459 | now I have that kind of information.
3460 |
3461 | 865
3462 | 00:41:19,710 --> 00:41:21,710
3463 | I also can use these tempo sliders.
3464 |
3465 | 866
3466 | 00:41:21,779 --> 00:41:25,948
3467 | For example if I touch it right now, hold on a second.
3468 |
3469 | 867
3470 | 00:41:26,017 --> 00:41:27,817
3471 | tempo deck one 0% adjustable.
3472 |
3473 | 868
3474 | 00:41:27,885 --> 00:41:29,819
3475 | So we hear it's at its standard playback speed, but
3476 |
3477 | 869
3478 | 00:41:29,888 --> 00:41:34,623
3479 | if I slow it down using the DJ controller and
3480 |
3481 | 870
3482 | 00:41:34,692 --> 00:41:35,391
3483 | I touch it again.
3484 |
3485 | 871
3486 | 00:41:35,459 --> 00:41:38,227
3487 | Tempo deck one, -7.1%, adjustable.
3488 |
3489 | 872
3490 | 00:41:38,295 --> 00:41:40,996
3491 | We can hear exactly how far I've slown that track down,
3492 |
3493 | 873
3494 | 00:41:41,065 --> 00:41:42,131
3495 | that's really cool.
3496 |
3497 | 874
3498 | 00:41:42,199 --> 00:41:44,633
3499 | I also can use these multi-dimensional effect pads
3500 |
3501 | 875
3502 | 00:41:44,702 --> 00:41:47,570
3503 | for example if I touch it the first time Effects pad,
3504 |
3505 | 876
3506 | 00:41:47,638 --> 00:41:48,404
3507 | deck one.
3508 |
3509 | 877
3510 | 00:41:48,473 --> 00:41:54,576
3511 | But the second time.
3512 |
3513 | 878
3514 | 00:41:54,645 --> 00:41:55,744
3515 | Really cool stuff, right.
3516 |
3517 | 879
3518 | 00:41:55,813 --> 00:41:59,448
3519 | So between these effects pads, this external controller, and
3520 |
3521 | 880
3522 | 00:41:59,517 --> 00:42:00,916
3523 | all this accessible UI.
3524 |
3525 | 881
3526 | 00:42:00,985 --> 00:42:02,385
3527 | I can do a pretty cool performance.
3528 |
3529 | 882
3530 | 00:42:02,453 --> 00:42:05,187
3531 | So I'd like to go ahead and ask the stage crew to please
3532 |
3533 | 883
3534 | 00:42:05,256 --> 00:42:07,189
3535 | take VoiceOver off of the PA systems.
3536 |
3537 | 884
3538 | 00:42:07,258 --> 00:42:09,892
3539 | So that it's only available to me in my headphones.
3540 |
3541 | 885
3542 | 00:42:09,961 --> 00:42:11,293
3543 | Play deck one.
3544 |
3545 | 886
3546 | 00:42:11,362 --> 00:42:12,294
3547 | Cool, thank you very much.
3548 |
3549 | 887
3550 | 00:42:12,363 --> 00:42:13,996
3551 | And I'm gonna mix for you now.
3552 |
3553 | 888
3554 | 00:42:14,065 --> 00:42:14,496
3555 | Here we go.
3556 |
3557 | 889
3558 | 00:42:14,565 --> 00:42:24,607
3559 | [MUSIC]
3560 |
3561 | 890
3562 | 00:42:39,557 --> 00:42:44,960
3563 | [APPLAUSE] So because of the effort
3564 |
3565 | 891
3566 | 00:42:45,029 --> 00:42:48,030
3567 | that their team put in, people with vision impairments,
3568 |
3569 | 892
3570 | 00:42:48,099 --> 00:42:50,900
3571 | like Ryan, can DJ just as well as anybody else.
3572 |
3573 | 893
3574 | 00:42:50,969 --> 00:42:53,602
3575 | It's something that he loves to do, and it's only possible
3576 |
3577 | 894
3578 | 00:42:53,671 --> 00:42:56,339
3579 | because somebody at that company decided that it was
3580 |
3581 | 895
3582 | 00:42:56,407 --> 00:42:59,943
3583 | worth it.
3584 |
3585 | 896
3586 | 00:43:00,011 --> 00:43:01,143
3587 | Thank you.
3588 | 谢谢大家!(一片掌声雷鸣之中
3589 |
3590 | 897
3591 | 00:43:01,212 --> 00:43:04,413
3592 | [APPLAUSE] For more,
3593 | 本系列完美落幕。我们明年再见)
3594 |
3595 | 898
3596 | 00:43:04,482 --> 00:43:12,988
3597 | please visit us at stanford.edu
3598 | >> 更多课程详见 stanford.edu
3599 |
--------------------------------------------------------------------------------
/tools/download.md:
--------------------------------------------------------------------------------
1 | [返回主页](../README.md) / [Back to Main Page](../en/README.md)
2 |
3 | # Videos
4 |
5 | 1. [Introduction to iOS 10, Xcode 8 and Swift 3](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/02/4d/e9/024de95b-8afc-89b9-e4ba-ef8e08d5d13f/324-3685031694599443811-01_1_09_17_720p3000_for_iTunes.m4v) -- [中英字幕](https://raw.githubusercontent.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/master/subtitles/1.%20Introduction%20to%20iOS%2010%2C%20Xcode%208%20and%20Swift%203.srt)
6 | 2. [MVC; iOS, Xcode and Swift Demonstration](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/a5/2c/bd/a52cbd78-81b0-21f4-ddd2-938d88736d1e/305-7182155496523276740-02_1_11_17_720p3000cc.m4v) -- [中英字幕](https://raw.githubusercontent.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/master/subtitles/2.%20MVC%3B%20iOS%2C%20Xcode%20and%20Swift%20Demonstration.srt)
7 | 3. [More Swift and the Foundation Framework](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/06/89/5f/06895f76-941c-d5c7-c67a-b4a344ff04da/319-4626069356218693519-03_1_18_17_720p3mb_iTunes.m4v) -- [中英字幕](https://raw.githubusercontent.com/ApolloZhu/Developing-iOS-10-Apps-with-Swift/master/subtitles/3.%20More%20Swift%20and%20the%20Foundation%20Framework.srt)
8 | 4. [Views](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic82/v4/2f/19/00/2f190095-0ad9-68da-de79-460b9b9a5b21/307-1808792045946883749-04_1_23_17_1080p_1_720p_3000.m4v)
9 | 5. [Gestures and Multiple MVCs](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/3b/e8/87/3be887ea-089b-2532-81eb-3f21a789d79c/328-6978379452515215276-05_1_25_17_720p_3000cc.m4v)
10 | 6. [Multiple MVCs, View Controller Lifecycle, and Memory Management](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/ac/9b/8d/ac9b8d88-ca19-3364-c91c-ad88b76457aa/330-554709660381912333-06_1_30_17_720p_3mbcc.m4v)
11 | 7. [Error Handling, Extensions, Protocols, Delegation, and Scroll View](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/f4/06/12/f406127e-4cdc-3859-555e-49872b7736d0/322-5522795565946608562-07_CS193p_2_01_17_720p_3000cc.m4v)
12 | 8. [Multithreading and Text Field](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/b7/64/30/b76430e9-a1e1-d257-c14f-b822dd314749/327-2534985180508386683-08_CS193p_2_06_17_720p_3000cc.m4v)
13 | 9. [Table View](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/2f/e0/34/2fe0348d-de16-64ba-0f94-0d0dac7121bb/337-8752859105577614662-09_CS193p_2_08_17_720p_3000.m4v)
14 | 10. [Core Data](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/84/a3/a3/84a3a3aa-b6f5-fe7c-2cc5-9719f2049046/311-2755894078252338227-10_CS193p_2_13_17_revised_WIP03_720p3000.mp4)
15 | 11. [Core Data Demo](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/dd/07/87/dd07870d-cb3c-c2fb-63b0-e8453452b0b2/318-3789265740124671308-11_CS193p_2_15_17_720p_3000.m4v)
16 | 12. [Autolayout](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/c7/05/85/c7058540-443c-4cc8-74fc-ef151c6e25f3/316-5259175746296795476-12_CS193p_2_22_17_revised_WIP03_720p3000cc.mp4)
17 | 13. [Timer and Animation](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/dd/9e/bc/dd9ebcdd-f8ad-05bd-e0a1-bc8163f78125/303-6364109281891900174-13_CS193p_2_27_17_720p3000cc.mp4)
18 | 14. [Dynamic Animation Demo](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/69/e6/a6/69e6a628-a269-e496-b51d-afaf25c114a1/323-8980879071774720493-14_3_01_17_720p3000cc.mp4)
19 | 15. [More Segues](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/6b/5f/54/6b5f5450-12d7-23cf-a3ec-2d313923875c/324-2875002592034152487-15_3_06_17_wip2_1080p_720p_3mb_cc.m4v)
20 | 16. [Alerts and Action Sheets, Notifications, Application Lifecycle, and Persistence](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic127/v4/69/f6/c7/69f6c757-e44e-245e-f539-bee224372dc6/323-7683342428341604999-16_3_08_17_720p_3000cc.m4v)
21 | 17. [Accessibility](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic127/v4/7d/68/df/7d68dfc6-f9eb-c72c-905c-7557d96a8b5b/330-3844304494261784016-17_3_13_17_2_720p_3000cc.m4v)
22 |
23 | # Slides
24 |
25 | 1. [Lecture 1 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/4a/a7/26/4aa726ce-b9a0-dfc6-1caa-a0c21279f4fe/302-9205777791325237790-CS193P_Winter_17_Lecture_1.pdf)
26 | 2. [Lecture 2 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/3e/4f/87/3e4f87b1-ff63-7239-d64a-42a11e95a071/309-1216292682689348645-CS193P_Winter_17_Lecture_2.pdf)
27 | 3. [Lecture 3 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/3b/26/03/3b260345-a591-ad12-a089-cb5bd3e6fcc5/306-3349052672936698336-CS193P_Winter_17_Lecture_3.pdf)
28 | 4. [Lecture 4 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/85/52/eb/8552ebd3-2577-33c2-5e15-ea0b21109d10/322-2432714053453526314-CS193P_Winter_17_Lecture_4.pdf)
29 | 5. [Lecture 5 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/10/9d/2b/109d2b59-c432-5e4e-63a4-40ccdd9f04dd/321-3063962921399737466-CS193P_Winter_17_Lecture_5.pdf)
30 | 6. [Lecture 6 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/03/b9/48/03b94846-86b1-78b4-4f0d-db883b178a93/329-5253968848372497904-CS193P_Winter_17_Lecture_6.pdf)
31 | 7. [Lecture 7 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/65/32/4e/65324e1a-3d03-cf1b-2bf8-ea23c42f450b/332-5273798659857609329-CS193P_Winter_17_Lecture_7.pdf)
32 | 8. [Lecture 8 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/c6/24/c4/c624c4a1-781c-613f-f86f-19c9b013d92a/329-5089714432926654345-CS193P_Winter_17_Lecture_8.pdf)
33 | 9. [Lecture 9 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/8f/44/45/8f4445c4-76f3-f356-69c3-3cd384470cc9/314-2744839717659725615-CS193P_Winter_17_Lecture_9.pdf)
34 | 10. [Lecture 10 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/6f/54/7c/6f547cc8-1d90-88c8-77e4-d9ad9a413144/312-2771300030580731448-CS193P_Winter_17_Lecture_10.pdf)
35 | 12. [Lecture 12 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/38/ff/0d/38ff0d79-0ba4-94a2-2d3f-2e3e62ffbe23/309-3567392098680090005-CS193P_Winter_17_Lecture_12.pdf)
36 | 13. [Lecture 13 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/8e/4e/5d/8e4e5d8d-d403-28ff-3a2b-47fe17a00460/306-2848100867125253549-CS193P_Winter_17_Lecture_13.pdf)
37 | 15. [Lecture 15 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/82/e7/17/82e71729-4a3b-f604-4d4b-588a0b64c5de/311-6653904285911219618-CS193P_Winter_17_Lecture_15.pdf)
38 | 16. [Lecture 16 Slides](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic127/v4/d2/5f/36/d25f36ef-e1d7-c296-9094-621db387fea6/319-5542480879425152826-CS193P_Winter_17_Lecture_16.pdf)
39 |
40 | # Demo Code
41 |
42 | 4. [Lecture 4 Demo Code: FaceIt](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/90/23/06/90230676-8974-d6f4-8730-db23b02981d4/328-3425656378839915562-L4_Demo_Code.pdf)
43 | 5. [Lecture 5 Demo Code: FaceIt](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/6e/d9/4d/6ed94dd8-30e3-f0d4-0646-0b55d300a3d2/329-3399216634488067626-L5_Demo_Code.pdf)
44 | 6. [Lecture 6 Demo Code: FaceIt](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/51/0b/bc/510bbce2-ec82-b3ab-de8f-508ba60f1be9/334-3428961349568251114-L6_Demo_Code.pdf)
45 | 7. [Lecture 7 Demo Code: Cassini](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/7a/ac/a7/7aaca767-9f2c-8bc3-a32a-3c3456660545/330-3352947087241042856-L7_Demo_Code.pdf)
46 | 8. [Lecture 8 Demo Code: Cassini](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/c2/4b/5e/c24b5e00-66b3-6e1c-c024-a98b21736424/311-1937232581840857786-L8_Demo_Code.pdf)
47 | 9. [Lecture 9 Demo Code: Smashtag](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/bd/b9/a3/bdb9a33e-0801-7cd3-5afc-849b44b0fa6d/316-1975239713004461915-L9_Demo_Code.pdf)
48 | 11. [Lecture 11 Demo Code: Smashtag](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/11/da/76/11da7624-122d-4667-3b7c-84077311be31/308-6440268317978219720-L11_Demo_Code.pdf)
49 | 13. [Lecture 13 Demo Code: FaceIt](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/88/4e/7c/884e7c7c-f164-5262-6884-4734c0101c0f/302-4707211118905059285-L13_Demo_Code.pdf)
50 | 14. [Lecture 14 Demo Code: Asteroids](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/b0/d3/53/b0d35343-960c-c35c-cc51-6a6161d2fe56/308-3158927732347667387-L14_Demo_Code.pdf)
51 | 15. [Lecture 15 Demo Code: FaceIt Segues](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/b0/64/55/b064559c-073f-a6b5-38a8-bc1b1519332f/307-7933058492198201398-L15_Demo_Code.pdf)
52 |
53 | # Reading Assignments
54 |
55 | 1. [Intro to Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/7d/38/f2/7d38f27a-3b82-de90-2f2c-2ee40514a56b/329-3366122602226359241-CS193P_Winter_17_Reading_1.pdf)
56 | 2. [More Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/50/27/6e/50276e9c-bb5a-2cd8-db64-c027a1f98507/318-8166708043639963524-CS193P_Winter_17_Reading_2.pdf)
57 | 3. [The Rest of Swift](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/81/cf/fd/81cffd52-6c5a-1ecb-7366-875a41ad6465/303-5453919407785590613-CS193P_Winter_17_Reading_3.pdf)
58 |
59 | # Programming Projects
60 |
61 | 1. [Calculator](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/3b/5f/8a/3b5f8a08-0535-8a32-0854-8a1d4c44fc83/330-8784676202759607348-CS193P_Winter_17_Project_1.pdf)
62 | 2. [Calculator Brain](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic122/v4/16/6d/ee/166dee9f-1ff6-f7d1-99cc-2590c616c7b3/334-4539701711666409931-CS193P_Winter_17_Assignment_2_v4.pdf)
63 | 3. [Graphing Calculator](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/d3/cc/f8/d3ccf813-811f-0a8a-0f97-a3da51065fcb/305-7790343223312375480-CS193P_Winter_17_Assignment_3.pdf)
64 | 4. [Smashtag Mentions](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/9f/f5/20/9ff520eb-7558-aa61-121f-841efed2460f/327-6109771528612506048-CS193P_Winter_17_Assignment_4.pdf)
65 | 5. [Smashtag Mention Popularity](https://itunesu-assets.itunes.apple.com/apple-assets-us-std-000001/CobaltPublic111/v4/53/93/f1/5393f1c8-8612-b547-1cc7-06ba86fa486a/322-1087034889572316150-CS193P_Winter_17_Assignment_5.pdf)
66 |
67 |
--------------------------------------------------------------------------------
/tools/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Apollo Zhu on 3/12/17.
3 | // This work is licensed under a
4 | // Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License.
5 | //
6 |
7 | import Foundation
8 | import AppKit
9 |
10 | /// itunes.apple.com/us/course/developing-ios-10-apps-with-swift/id<#iTunesUCourseID#>
11 | let iTunesUCourseID = 1198467120
12 |
13 | enum ResourceType: String, CustomStringConvertible {
14 | // Raw Type: video/x-m4v, video/mp4
15 | case video = "Video"
16 | // Raw Type: application/pdf
17 | case slides = "Slides"
18 | case demoCode = "Demo Code"
19 | case readingAssignment = "Reading Assignment"
20 | case programmingProject = "Programming Project"
21 |
22 | static let all: LazyCollection<[ResourceType]> = [.video, .slides, .demoCode, .readingAssignment, .programmingProject].lazy
23 |
24 | var description: String {
25 | switch self {
26 | case .slides, .demoCode:
27 | return rawValue
28 | default:
29 | return "\(rawValue)s"
30 | }
31 | }
32 | }
33 |
34 | struct Resource: CustomStringConvertible {
35 | let index: Int
36 | let title: String
37 | let type: ResourceType
38 | let url: String
39 |
40 | init(title: String, rawType: String, url: String) {
41 | self.url = url
42 |
43 | if rawType.contains("video") {
44 | type = .video
45 | } else if let resType = ResourceType.all.first(where: { title.contains($0.rawValue) }) {
46 | type = resType
47 | } else {
48 | fatalError("Unknown Raw Type \(rawType)")
49 | }
50 |
51 | var parts: [String]
52 | if type == .video {
53 | // 4. Views -> index: 4, title: Views
54 | parts = title.components(separatedBy: ". ")
55 | } else if [.readingAssignment, .programmingProject].contains(type) {
56 | // Reading Assignment 2: More Swift -> index: 2, title: More Swift
57 | // Programming Project 2: Calculator Brain -> index: 2, title: Calculator Brain
58 | parts = title.components(separatedBy: ": ")
59 | parts[0] = parts[0].components(separatedBy: " ")[2]
60 | } else {
61 | // Lecture 6 Slides -> index: 6, title: Lecture 6 Slides
62 | // Lecture 9 Demo Code: Smashtag -> index: 9, title: Lecture 9 Demo Code: Smashtag
63 | parts = [title.components(separatedBy: " ")[1], title]
64 | }
65 | self.index = Int(parts[0])!
66 | self.title = parts[1]
67 | }
68 |
69 | var description: String {
70 | return "\(index). [\(title)](\(url))"
71 | }
72 | }
73 |
74 | /* Example XML
75 |
76 |
77 | Paul Hegarty
78 |
79 |
80 | ]]>
81 |
82 | 1/COETAIHAJLZIQXJI/MAEC2FBSEERRMTUH
83 | 2017-03-10T18:19:21PST
84 | 2017-03-10T17:36:29PST
85 |
86 |
87 |
88 |
89 |
90 | */
91 | class ParsingDelegate: NSObject, XMLParserDelegate {
92 | var resources = [Resource]()
93 |
94 | var title: String?
95 | var isParsingTitle = false
96 | var type: String?
97 | var url: String?
98 |
99 | func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
100 | if elementName == "link" {
101 | type = attributeDict["type"]
102 | url = attributeDict["href"]
103 | } else if elementName == "title" {
104 | isParsingTitle = true
105 | }
106 | }
107 |
108 | func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
109 | if isParsingTitle {
110 | if let title = String(data: CDATABlock, encoding: .utf8) {
111 | self.title = title
112 | } else {
113 | fatalError("Unable to parse title from \(CDATABlock)")
114 | }
115 | }
116 | }
117 |
118 | func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
119 | if elementName == "title" {
120 | isParsingTitle = false
121 | } else if elementName == "entry" {
122 | resources.append(Resource(title: title!, rawType: type!, url: url!))
123 | title = nil
124 | isParsingTitle = false
125 | type = nil
126 | url = nil
127 | }
128 | }
129 |
130 | func parserDidEndDocument(_ parser: XMLParser) {
131 | let sorted = ResourceType.all.map { [resources] type in
132 | resources.filter { $0.type == type } .sorted { $0.index < $1.index }
133 | }
134 |
135 | var out = "[返回主页](../README.md) / [Back to Main Page](../en/README.md)\n\n"
136 | for (index, type) in ResourceType.all.enumerated() {
137 | guard !sorted[index].isEmpty else { fatalError("Missing Resources of Type \(type)") }
138 | out += "# \(type)\n\n"
139 | + "\(sorted[index].reduce("") { "\($0)\($1)\n" })\n"
140 | }
141 |
142 | let cwd = CommandLine.arguments.first { $0.contains(#file) } ?? FileManager.default.currentDirectoryPath
143 | let url = URL(fileURLWithPath: cwd).deletingLastPathComponent().appendingPathComponent("download.md")
144 | do {
145 | try out.write(to: url, atomically: true, encoding: .utf8)
146 | #if swift(>=4)
147 | let workspace = NSWorkspace.shared
148 | #else
149 | let workspace = NSWorkspace.shared()
150 | #endif
151 | workspace.activateFileViewerSelecting([url])
152 | } catch {
153 | print(out)
154 | }
155 | }
156 | }
157 |
158 | let url = URL(string: "https://itunesu.itunes.apple.com/WebObjects/LZDirectory.woa/ra/directory/courses/\(iTunesUCourseID)/feed")!
159 | let parser = XMLParser(contentsOf: url)!
160 | let delegate = ParsingDelegate()
161 | parser.delegate = delegate
162 | parser.parse()
163 |
--------------------------------------------------------------------------------
/tools/update.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 52D71C3B1E7612ED0036EE1C /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D71C3A1E7612ED0036EE1C /* main.swift */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 522CA2021E75E64B00EE2E2F /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = /usr/share/man/man1/;
18 | dstSubfolderSpec = 0;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 1;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 522CA2041E75E64B00EE2E2F /* update */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = update; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 52D71C3A1E7612ED0036EE1C /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = SOURCE_ROOT; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 522CA2011E75E64B00EE2E2F /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 522CA1FB1E75E64B00EE2E2F = {
42 | isa = PBXGroup;
43 | children = (
44 | 52D71C3A1E7612ED0036EE1C /* main.swift */,
45 | 522CA2051E75E64B00EE2E2F /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 522CA2051E75E64B00EE2E2F /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 522CA2041E75E64B00EE2E2F /* update */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | /* End PBXGroup section */
58 |
59 | /* Begin PBXNativeTarget section */
60 | 522CA2031E75E64B00EE2E2F /* update */ = {
61 | isa = PBXNativeTarget;
62 | buildConfigurationList = 522CA20B1E75E64B00EE2E2F /* Build configuration list for PBXNativeTarget "update" */;
63 | buildPhases = (
64 | 522CA2001E75E64B00EE2E2F /* Sources */,
65 | 522CA2011E75E64B00EE2E2F /* Frameworks */,
66 | 522CA2021E75E64B00EE2E2F /* CopyFiles */,
67 | );
68 | buildRules = (
69 | );
70 | dependencies = (
71 | );
72 | name = update;
73 | productName = update;
74 | productReference = 522CA2041E75E64B00EE2E2F /* update */;
75 | productType = "com.apple.product-type.tool";
76 | };
77 | /* End PBXNativeTarget section */
78 |
79 | /* Begin PBXProject section */
80 | 522CA1FC1E75E64B00EE2E2F /* Project object */ = {
81 | isa = PBXProject;
82 | attributes = {
83 | LastSwiftUpdateCheck = 0820;
84 | LastUpgradeCheck = 0900;
85 | ORGANIZATIONNAME = WWITDC;
86 | TargetAttributes = {
87 | 522CA2031E75E64B00EE2E2F = {
88 | CreatedOnToolsVersion = 8.2.1;
89 | DevelopmentTeam = 2H866F22W7;
90 | LastSwiftMigration = 0900;
91 | ProvisioningStyle = Automatic;
92 | };
93 | };
94 | };
95 | buildConfigurationList = 522CA1FF1E75E64B00EE2E2F /* Build configuration list for PBXProject "update" */;
96 | compatibilityVersion = "Xcode 3.2";
97 | developmentRegion = English;
98 | hasScannedForEncodings = 0;
99 | knownRegions = (
100 | en,
101 | );
102 | mainGroup = 522CA1FB1E75E64B00EE2E2F;
103 | productRefGroup = 522CA2051E75E64B00EE2E2F /* Products */;
104 | projectDirPath = "";
105 | projectRoot = "";
106 | targets = (
107 | 522CA2031E75E64B00EE2E2F /* update */,
108 | );
109 | };
110 | /* End PBXProject section */
111 |
112 | /* Begin PBXSourcesBuildPhase section */
113 | 522CA2001E75E64B00EE2E2F /* Sources */ = {
114 | isa = PBXSourcesBuildPhase;
115 | buildActionMask = 2147483647;
116 | files = (
117 | 52D71C3B1E7612ED0036EE1C /* main.swift in Sources */,
118 | );
119 | runOnlyForDeploymentPostprocessing = 0;
120 | };
121 | /* End PBXSourcesBuildPhase section */
122 |
123 | /* Begin XCBuildConfiguration section */
124 | 522CA2091E75E64B00EE2E2F /* Debug */ = {
125 | isa = XCBuildConfiguration;
126 | buildSettings = {
127 | ALWAYS_SEARCH_USER_PATHS = NO;
128 | CLANG_ANALYZER_NONNULL = YES;
129 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
130 | CLANG_CXX_LIBRARY = "libc++";
131 | CLANG_ENABLE_MODULES = YES;
132 | CLANG_ENABLE_OBJC_ARC = YES;
133 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
134 | CLANG_WARN_BOOL_CONVERSION = YES;
135 | CLANG_WARN_COMMA = YES;
136 | CLANG_WARN_CONSTANT_CONVERSION = YES;
137 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
138 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
139 | CLANG_WARN_EMPTY_BODY = YES;
140 | CLANG_WARN_ENUM_CONVERSION = YES;
141 | CLANG_WARN_INFINITE_RECURSION = YES;
142 | CLANG_WARN_INT_CONVERSION = YES;
143 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
144 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
145 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
146 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
147 | CLANG_WARN_STRICT_PROTOTYPES = YES;
148 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
149 | CLANG_WARN_UNREACHABLE_CODE = YES;
150 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
151 | CODE_SIGN_IDENTITY = "-";
152 | COPY_PHASE_STRIP = NO;
153 | DEBUG_INFORMATION_FORMAT = dwarf;
154 | ENABLE_STRICT_OBJC_MSGSEND = YES;
155 | ENABLE_TESTABILITY = YES;
156 | GCC_C_LANGUAGE_STANDARD = gnu99;
157 | GCC_DYNAMIC_NO_PIC = NO;
158 | GCC_NO_COMMON_BLOCKS = YES;
159 | GCC_OPTIMIZATION_LEVEL = 0;
160 | GCC_PREPROCESSOR_DEFINITIONS = (
161 | "DEBUG=1",
162 | "$(inherited)",
163 | );
164 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
165 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
166 | GCC_WARN_UNDECLARED_SELECTOR = YES;
167 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
168 | GCC_WARN_UNUSED_FUNCTION = YES;
169 | GCC_WARN_UNUSED_VARIABLE = YES;
170 | MACOSX_DEPLOYMENT_TARGET = 10.9;
171 | MTL_ENABLE_DEBUG_INFO = YES;
172 | ONLY_ACTIVE_ARCH = YES;
173 | SDKROOT = macosx;
174 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
175 | };
176 | name = Debug;
177 | };
178 | 522CA20A1E75E64B00EE2E2F /* Release */ = {
179 | isa = XCBuildConfiguration;
180 | buildSettings = {
181 | ALWAYS_SEARCH_USER_PATHS = NO;
182 | CLANG_ANALYZER_NONNULL = YES;
183 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
184 | CLANG_CXX_LIBRARY = "libc++";
185 | CLANG_ENABLE_MODULES = YES;
186 | CLANG_ENABLE_OBJC_ARC = YES;
187 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
188 | CLANG_WARN_BOOL_CONVERSION = YES;
189 | CLANG_WARN_COMMA = YES;
190 | CLANG_WARN_CONSTANT_CONVERSION = YES;
191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
192 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
193 | CLANG_WARN_EMPTY_BODY = YES;
194 | CLANG_WARN_ENUM_CONVERSION = YES;
195 | CLANG_WARN_INFINITE_RECURSION = YES;
196 | CLANG_WARN_INT_CONVERSION = YES;
197 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
198 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
200 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
201 | CLANG_WARN_STRICT_PROTOTYPES = YES;
202 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
203 | CLANG_WARN_UNREACHABLE_CODE = YES;
204 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
205 | CODE_SIGN_IDENTITY = "-";
206 | COPY_PHASE_STRIP = NO;
207 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
208 | ENABLE_NS_ASSERTIONS = NO;
209 | ENABLE_STRICT_OBJC_MSGSEND = YES;
210 | GCC_C_LANGUAGE_STANDARD = gnu99;
211 | GCC_NO_COMMON_BLOCKS = YES;
212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
214 | GCC_WARN_UNDECLARED_SELECTOR = YES;
215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
216 | GCC_WARN_UNUSED_FUNCTION = YES;
217 | GCC_WARN_UNUSED_VARIABLE = YES;
218 | MACOSX_DEPLOYMENT_TARGET = 10.9;
219 | MTL_ENABLE_DEBUG_INFO = NO;
220 | SDKROOT = macosx;
221 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
222 | };
223 | name = Release;
224 | };
225 | 522CA20C1E75E64B00EE2E2F /* Debug */ = {
226 | isa = XCBuildConfiguration;
227 | buildSettings = {
228 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/$(CONFIGURATION)";
229 | DEVELOPMENT_TEAM = 2H866F22W7;
230 | PRODUCT_NAME = "$(TARGET_NAME)";
231 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
232 | SWIFT_VERSION = 4.0;
233 | };
234 | name = Debug;
235 | };
236 | 522CA20D1E75E64B00EE2E2F /* Release */ = {
237 | isa = XCBuildConfiguration;
238 | buildSettings = {
239 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/$(CONFIGURATION)";
240 | DEVELOPMENT_TEAM = 2H866F22W7;
241 | PRODUCT_NAME = "$(TARGET_NAME)";
242 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
243 | SWIFT_VERSION = 4.0;
244 | };
245 | name = Release;
246 | };
247 | /* End XCBuildConfiguration section */
248 |
249 | /* Begin XCConfigurationList section */
250 | 522CA1FF1E75E64B00EE2E2F /* Build configuration list for PBXProject "update" */ = {
251 | isa = XCConfigurationList;
252 | buildConfigurations = (
253 | 522CA2091E75E64B00EE2E2F /* Debug */,
254 | 522CA20A1E75E64B00EE2E2F /* Release */,
255 | );
256 | defaultConfigurationIsVisible = 0;
257 | defaultConfigurationName = Release;
258 | };
259 | 522CA20B1E75E64B00EE2E2F /* Build configuration list for PBXNativeTarget "update" */ = {
260 | isa = XCConfigurationList;
261 | buildConfigurations = (
262 | 522CA20C1E75E64B00EE2E2F /* Debug */,
263 | 522CA20D1E75E64B00EE2E2F /* Release */,
264 | );
265 | defaultConfigurationIsVisible = 0;
266 | defaultConfigurationName = Release;
267 | };
268 | /* End XCConfigurationList section */
269 | };
270 | rootObject = 522CA1FC1E75E64B00EE2E2F /* Project object */;
271 | }
272 |
--------------------------------------------------------------------------------
/tools/update.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/translation-style-guide.md:
--------------------------------------------------------------------------------
1 | # 翻译标准/校对规则
2 |
3 | ## 基本要求
4 |
5 | 1. 请大家翻译和校对的时候尽量对照原视频,结合上下文,不要望文生义
6 | 2. 如保持英文顺序会影响中文理解,为保证行文流畅,应采用理解优先原则,优先按中文断句
7 | 3. 当说话的人变更时,请加 `>>` 来区分。如:Question? >> Is it? >> Yes.
8 | 4. 出现 Okay,All Right,Now 等语气词,请结合上下文选择合适的翻译,或省略不翻
9 | 5. 学生提问的部分如果听不清楚,字幕也不全([INAUDIBLE]),但是老师回答时候把问题复述了一遍,字幕可译为 `>> [学生提问]`
10 | 6. 出现 [COUGH],[LAUGH],[NOISE],[BLANK_AUDIO],[INAUDIBLE] 等,请自行把握,可结合上下文选择省略不翻译
11 | 7. 卖萌请不要使用字符表情,比如(*3)看起来就像是备注;如果是标注说了三遍,请使用 x3 标记
12 |
13 | ## 格式要求
14 |
15 | 1. 不要合并多条**字幕**,两条字幕之间保持一个空行
16 | 2. 中英文字幕**开头结尾**均不留空格,以 Unix 样式的 LF (Line Feed 的缩写,即 \n) 换行
17 | 3. 省略字幕**开头结尾**不影响表意的标点。如保留问号,但省略如逗号、句号等
18 | 4. 除了 `[`,`]`,和 `>>` 以外使用全角中文标点,如果可能,使用中文数字
19 | 5. 保证每一条字幕中最多两行,一行英文一行翻译,翻译不会过长
20 | 6. 英文和阿拉伯数字同中文之间应当有一个空格
21 | 7. 如遇到英文词汇或阿拉伯数字和标点符号相邻的情况,则不需要再留空格
22 |
23 | 例:就算是最新的 iPad,也不能用 Swift Playgrounds 打包应用。
24 |
25 | ## 错误修正
26 |
27 | 1. 修改错别字,明显的笔误,大小写错误(包括原英文字幕中的错误)
28 | 2. 如能找到对应的 Swift Evolution 编号,以类似(在 SE-0065 之前)… 注明
29 | 3. 如能确定特定的 Swift 语言版本,以类似(在 Swift 4 之前)… 或(对于 Swift 3)… 注明
30 | 4. 如果完全错误,尝试以类似 …(误:原因)或(注:补充)说明。如空间不够,可适当调整上下文。参考第三课 1303 和 420
31 |
32 | ## 翻译术语(Terminology)的要求
33 |
34 | #### 术语的基本处理:
35 |
36 | 1. 尽量和已翻译的内容保持一致
37 | 2. 参考 [术语的特殊处理](#术语的特殊处理)
38 | 3. 参考 [Apple Developer 网页中文版](https://developer.apple.com/cn/)
39 | 4. 参考历年 [iOS 8](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift) 和 [iOS 9](https://github.com/SwiftGGTeam/Developing-iOS-9-Apps-with-Swift) 的翻译
40 | 5. 参考 [《The Swift Programming Language》中文版](http://gg.swiftguide.cn/) 及其 [术语表](https://github.com/numbbbbb/the-swift-programming-language-in-chinese/issues/62)
41 | 6. 参考该术语在其它编程语言中的翻译,可以使用 [微软官方术语搜索](https://www.microsoft.com/Language/zh-cn/Search.aspx) 等搜索引擎
42 | 7. 如果以上都没有找到合适的结果,你可以
43 | 1. 在得到任务分配的 issue 下讨论
44 | 2. 直接使用英文原文
45 | 3. 自己决定一个合适的翻译
46 |
47 | #### 术语的特殊处理
48 |
49 | 1. 如果想在同时翻译并保留原文,请根据情况从以下的格式中选用一种
50 | 1. 用逗号隔开。例:这是 Navigator,导航面板
51 | 2. 用括号补充。例:MVC,即 Model(模型)-View(视图)-Controller(控制器)
52 | 2. 不翻译通用的名称,如 MVC,iPhone,Xcode,Storyboard 等
53 | 3. 不翻译直接引用的代码,包括但不限于
54 | - Swift 语言关键字:如 true,false 等
55 | - 类/结构体/元组类型的名称:如 UIView,String 等
56 | - 项目中的代码:如 var description 等
57 |
58 | **后期校对请参考以上标准对术语的使用进行统一**
59 |
60 | ## 补充说明
61 |
62 | > 为何没有完全采用之前的[校对规范](https://github.com/X140Yu/Developing_iOS_8_Apps_With_Swift/blob/master/proofread-rules.md)?
63 |
64 | 其一是因为确实有些因为 Swift 的更新需要修改的地方。其二是因为即使就像之前规则中说的,*“校对是一个很重要的部分,甚至比翻译还要重要”*,但是如果我们从翻译阶段就能做到统一规范,相信校对也能事半功倍。当然,既然这是新的规范,没经过实践验证,欢迎大家根据实际情况讨论后提出修订意见。
65 |
--------------------------------------------------------------------------------