原文:watchOS 4 Tutorial Part 3: Animation
作者:Audrey Tam
译者:kmyhy

更新说明: 本教程由 Audrey Tam 更新至 Swift 4/watchOS 4。原文作者是 Mic Pringle。

欢迎回到 watchOS 4 系列教程!

在教程(1)中,你学习了基本的 watchOS 4 开发,创建了你的第一个 interface controller。

在教程(2)中,你学习了如何在 app 中添加表格。

在这部教程(3)中,你将学习如何使用 watchOS 4 动画,在 app 中添加一个新的登机界面。

在这个过程中,你将学到:

  • 如何创建基于 image 的动画
  • 如何使用 watchOS 4 的动画 API

让我们立即开始吧!

注意:这部分教程基于教程(2)的工作基础之上。你可以用之前的项目开始,如果你想重新开始,也可以从这里下载代码。

开始

打开 Watch\Interface.storyboard,从 Object Library 中拖一个 interface controller 到故事板中。选中这个 interface controller,打开属性面板,将 Identifier 设置为 CheckIn。这样才能从 ScheduleInterfaceController 中呈现这个 interface controller。

然后,拖一个 group 到新的 interface controller 上。在属性面板中,修改属性:

  • 设置 Layout 为 Vertical。
  • 设置 Mode 为 Center。
  • 设置 Horizontal Alignment 为 Center。
  • 设置 Height 为 Relative to Container。

你的 interface controller 看起来应该像这样:

接下来,我们会构建一个 label-image-label 样的 group,和你创建表格行时差不多。

拖一个 group 到刚才的 group 中,在属性面板修改下列属性:

  • 设置 Spacing 为 4。
  • 设置 Horizontal Alignment 为 Center。
  • 设置 Width 为 Size To Fit Content。
  • 设置 Height 为 Fixed,值为 30 (比表格行略矮)。

在新 group 中添加一个 label 和一个 image。我们会设置 label,然后复制修改它,用于显示航班起点和终点。

选中 image,无论从故事板中还剩 document outline 中都可以。在属性面板中,修改其属性:

  • 设置 Image 为 Plane。
  • 设置 Tint 为 #FA114F (又是我们的 Air Aber 粉!)。
  • 设置 Vertical Alignment 为 Center。
  • 设置 Width 为 Fixed,值为 24。
  • 设置 Height 为 Fixed,值为 20。

和之前一样,这个图片不会被上色,你无法将它从 interface controller 的黑色背景中看见它。但你应该知道它是存在的。

选中 label,将 Text 设置为 MEL。将 Font 设置为 System,字体样式为 Semibold、大小为 20。最后,设置它的 Vertical alignment 为 Center,将它的宽、高都修改成 Size To Fit Content。

复制这个 label,然后将它粘贴到 image 旁边。将 text 修改为 SFO,Horizontal Alignment 设置为 Right。你的 interface controller 现在应该看起来是这个样子:

现在来添加一个大大的登机按钮。

添加登机按钮

从 Object Library 中拖一个按钮到 interface controller,将位置放到和起点、终点 label 同一个 group 中:

WatchKit 中的按钮非常灵活;你可以只使用它们的内置样式——这样你只能添加一种样式——你还可以将它们转换成布局 group,将其它界面元素添加进去以定制其外观。这就是我们接下来要做的。

选中按钮,在属性面板中修改下列属性:

  • 设置 Content 为 Group。
  • 设置 Horizontal Alignment 为 Center。
  • 设置 Vertical Alignment 为 Center。

现在的 interface controller 应该是这个样子:

你可能注意到了,当你修改按钮的 Content 属性时,在 document outline 中出现了一个新的 group:

你将用它作为登机按钮的背景。选中这个 group,在属性面板中修改属性:

  • 设置 Color 为 #FA114F。
  • 设置 Radius 为 39。
  • 设置 Width 为 Fixed,值为 78。
  • 设置 Height 为 Fixed,值为 78。

interface controller 现在是这个样子:

登机按钮开始有点样子了。唯一缺少的仅仅是一个标签,接下来我们就添加它。

拖一个 label 到按钮下面的这个 group 中,然后选中 label。用属性面板修改其属性:

  • 设置 Text 为 Check In。
  • 设置 Font 为 System,字体样式为 Semibold 字体大小为 16。
  • 设置 Horizontal Alignment 为 Center。
  • 设置 Vertical Alignment 为 Center。

完成后的这个登机按钮长这个样子:

接下来应该专门为这个 controller 创建一个 WKInterfaceController 子类并修改 ScheduleInterfaceController 以便显示它。

创建 Controller

在项目导航器中,右键点击 Watch Extension 文件夹,选择 New File…。在对话框中选择 watchOS\Source\WatchKit Class 然后点 Next。文件名命名为 CheckInInterfaceController,继承自 WKInterfaceController,将 Language 设置为 Swift。

点击 Next、Create。

新文件打开后,删除 3 个空方法,只留下 import 语句和类定义。

然后,在类头部添加:

@IBOutlet var backgroundGroup: WKInterfaceGroup!
@IBOutlet var originLabel: WKInterfaceLabel!
@IBOutlet var destinationLabel: WKInterfaceLabel!

这里为最外层的 group 和两个 label 都创建了 outlet。后面我们会连接它们。

然后,在 outlet 下面添加:

var flight: Flight? {didSet {guard let flight = flight else { return }originLabel.setText(flight.origin)destinationLabel.setText(flight.destination)}
}

你应该知道了吧!这里,我们添加了一个可空的 Flight 对象,同时定义了一个属性观察器。当观察器触发时,我们队 flight 解包,如果解包成功,用这个 flight 来设置两个 label。这个套路你已经相当熟悉了,不是吗?

当 controller 被呈现时,我们必须对 flight 属性赋值。在 CheckInInterfaceController 中添加方法:

override func awake(withContext context: Any?) {super.awake(withContext: context)if let flight = context as? Flight {self.flight = flight}
}

这个你也应该很熟悉。我们首先解包 context 对象成一个 Flight 对象。如果解包成功,将它赋给 self.flight,这会触发属性观察器并更新 UI。

最后,在 awake(withContext:) 下面添加:

@IBAction func checkInButtonTapped() {// 1let duration = 0.35let delay = DispatchTime.now() + (duration + 0.15)// 2backgroundGroup.setBackgroundImageNamed("Progress")// 3backgroundGroup.startAnimatingWithImages(in: NSRange(location: 0, length: 10), duration: duration,repeatCount: 1)// 4DispatchQueue.main.asyncAfter(deadline: delay) { [weak self]in// 5self?.flight?.checkedIn = trueself?.dismiss()}
}

分成几个步骤:

  1. 这里创建了两个常量:一个是动画的时长,一个是当控制器解散时的延时。这 delay 没有使用 Double 类型,而是使用了 DispatchTime 类型,因为我们将在 GCD 中使用它。
  2. 加载一个名叫 Progress 的图片序列,并用作 backgroundGroup 的背景图片。布局 group 实现了 WKImageAnimatable 协议,这个协议允许我们播放图片序列。
  3. 播放动画序列。播放的范围指定为整个序列,repeatCount:1 表示动画只播放一次。
  4. WatchKit 没有完成处理块,因此只能用 GCD 延时回调来代替回调闭包。
  5. 在闭包中,你可以将航班标记为已登机,然后解散控制器。

现在需要在项目中添加用到的图片,以及连接 outlet 和一个 IBAction。

下载这个 zip 文件,解压缩,将文件夹整个拖到 Watch\Assets.xcassets。

确认你拖的是文件夹,而不是它的内容。这会在 asset catalog 中创建一个新的 group 叫做 Progress,其中包含以下几张图片:

添加完图片,就要连接 outlet 和按钮的 action 了。

打开 Watch\Interface.storyboard,选中我们的新 interface controller。在 Identity 面板中,修改 Custom Class\Class 为 CheckInInterfaceController:

在 document outline 中,右键点击 CheckIn 调出 outlets and actions 菜单。将 backgroundGroup 连接到 interface controller 最外层的 group:

在故事板中,连接 destinationLabel 到 SFO 标签,连接 originLabel 到 MEL 标签。

然后,连接 checkInButtonTapped 到圆圆的大按钮上:

在 Build & run 之前,还有最后一件事情,就是呈现这个 interface controller。

呈现控制器

打开 ScheduleInterfaceController.swift,找到 table(_:didSelectRowAt:) 方法,将它的内容修改为:

let flight = flights[rowIndex]
let controllers = ["Flight", "CheckIn"]
presentController(withNames: controllers, contexts: [flight, flight])

这里,我们从 flights 数组检索出 rowIndex 对应的 flight 对象,创建一个包含了要呈现的 2 个 interface 控制器的 identifier 的数组,并分别向它们传入两个 flight 作为 context。

Build & run。点击一个航班,你会两个 interface controller 显示出来。向左扫显示登机 controller,点击按钮播放动画并登机:

这看起来很好,但如果在 schedule interface controller 中能对已登机的航班加亮显示就更好了。我们将在下一节也就是本文的最后一节解决这个问题。

航班加亮

打开 FlightRowController.swift 添加下列方法:

func updateForCheckIn() {let color = UIColor(red: 90/255, green: 200/255, blue: 250/255, alpha: 1)planeImage.setTintColor(color)separator.setColor(color)
}

这里我们创建了一个 UIColor 实例,用它设置 planeImage 和 separator 的 tint 颜色。这个方法将在动画闭包中调用,因此颜色的改变是以动画的方式进行的。

然后,打开 ScheduleInterfaceController.swift 在 flights 属性后面添加:

var selectedIndex = 0

用这个属性记录当呈现两个 interface 控制器时选中的行。当表格行被选中时对这个属性赋值就好了。在 table(_:didSelectRowAt:) 中调用 presentController(withNames:contexts:) 的一句前添加:

selectedIndex = rowIndex

将 selectedIndex 设置为选中行。

最后,在 ScheduleInterfaceController 的 awake(withContext:) 方法后面添加:

override func didAppear() {super.didAppear()// 1guard flights[selectedIndex].checkedIn,let controller = flightsTable.rowController(at: selectedIndex) as? FlightRowController else {return}// 2animate(withDuration: 0.35) {// 3controller.updateForCheckIn()}
}

代码解释如下:

  1. 判断所选航班是否已经 check in,如果是,转换对应行索引的 row controller 为 FlightRowController 对象。
  2. 如果转换成功,用 WKInterfaceController 的 animation API 执行指定闭包,动画时长设置为 0.35 秒。
  3. 在闭包中,调用前面添加到 FlightRowController 中的方法,修改该表格行上的飞机图片和分隔线的颜色,给用户知道他们现在已经登记的航班。

Build & run。执行前面同样的步骤进行航班登机。当你返回 schedule interface controller,你会发现飞机图片和分隔线的颜色以一种渐变的方式发生了改变。

恭喜你!你已经完成了你的第一个 WatchKit 动画。

接下来做什么?

这里是本系列完成后的示例项目。

在这部分教程中,你学习了如何创建两个不同的 WatchKit 动画。第一个使用的是动画图片序列,第二个使用的是 WKInterfaceController 的 animation API。你现在已经可以为你自己的 watchOS 4 app 中添加大量的视觉效果了!

遗憾的是,本系列教程就到此为止了。

如果你有疑问或建议,请在下面的论坛中留言!

watchOS 4 教程(3):动画相关推荐

  1. XamarinAndroid组件教程设置动画的设置插值器

    XamarinAndroid组件教程设置动画的设置插值器 为动画设置插值器,可以使用BaseItemAnimator抽象类中的SetInterpolator()方法,其语法形式如下: public v ...

  2. XamarinAndroid组件教程设置动画的时长参数

    XamarinAndroid组件教程设置动画的时长参数 在添加动画的时候,开发者还可以动画参数进行设置,如动画持续的时长.插值器等.下面依次讲解动画参数的设置方法. 1.设置动画时长 设置动画持续的时 ...

  3. XamarinAndroid组件教程RecylerView动画组件使用动画(3)

    XamarinAndroid组件教程RecylerView动画组件使用动画(3) (8)打开Main.axml文件,构建主界面.代码如下: <?xml version="1.0&quo ...

  4. XamarinAndroid组件教程RecylerView动画组件使用动画(2)

    XamarinAndroid组件教程RecylerView动画组件使用动画(2) 如果开发者要为RecylerView的子元素添加动画效果,需要使用RecyclerView类中的SetItemAnim ...

  5. Xamarin Android组件篇教程RecylerView动画组件RecylerViewAnimators(1)

    Xamarin Android组件篇教程RecylerView动画组件RecylerViewAnimators(1) RecyclerView是比ListView和GridView更为强大的布局视图, ...

  6. WatchOS开发教程之四: Watch与 iPhone的通信和数据共享

    WatchOS 开发教程系列文章: WatchOS开发教程之一: Watch App架构及生命周期 WatchOS开发教程之二: 布局适配和系统Icon设计尺寸 WatchOS开发教程之三: 导航方式 ...

  7. WatchOS开发教程之一: Watch App架构及生命周期

    WatchOS 开发教程系列文章: WatchOS开发教程之一: Watch App架构及生命周期 WatchOS开发教程之二: 布局适配和系统Icon设计尺寸 WatchOS开发教程之三: 导航方式 ...

  8. Flash新手入门教程:动画补间和形状补间转

    Flash新手入门教程:动画补间和形状补间 2008-07-10 10:59:52  作者: 清风掠影  来源: 中国教程网论坛  浏览次数: 11930    评论 本文由 中国教程网 清风掠影 原 ...

  9. android 设置动画时长,XamarinAndroid组件教程设置动画的时长参数

    XamarinAndroid组件教程设置动画的时长参数 在添加动画的时候,开发者还可以动画参数进行设置,如动画持续的时长.插值器等.下面依次讲解动画参数的设置方法. 1.设置动画时长 设置动画持续的时 ...

  10. VideoScribe基础教程创建动画视频

    VideoScribe基础教程创建动画视频 全面的指南,充满了 Sparkol 首席培训师(VideoScribe 的创建者)的专家提示和技巧 课程英文名:VideoScribe Fundamenta ...

最新文章

  1. Django源码分析6:auth认证及登陆保持
  2. 在线作图|微生物多样性分析——丰度等级曲线
  3. WebSocket 学习
  4. 【Python反射】通过函数名称获取函数
  5. 数据可用不可见!揭秘蚂蚁区块链摩斯安全计算平台
  6. 验证码---H_img.php
  7. python中pandas安装视频教程_详解Python中pandas的安装操作说明(傻瓜版)
  8. 怎样下载C/C++的免费、开源且跨平台IDE——Code::Blocks
  9. 自己调试接口遇到的错误记录
  10. 第二次作业——个人项目实战之随机数独生成
  11. 木马的隐藏及其启动方式 (转)
  12. 关于显示器显示效果的调节(色温,6轴)
  13. 悉尼大学COMP5216Assignment2课业解析
  14. (一种因疏忽而发生的错误)Qt LNK2019:无法解析的外部符号
  15. 鬼故事之中学异事(01)
  16. 自建个人用服务器要多少钱,我想建立一个人网站,像19楼那样的论坛,是自建服务器便宜还是租用服务器便宜...
  17. C语言3067答案,教师招聘《小学教育心理学》通关试题每日练(2020年03月03日-3067)...
  18. CF727E. Games on a CD (Hash)
  19. 基于51单片机的智能门禁控制系统
  20. cf:B. Patchouli‘s Magical Talisman【数学贪心思维 + 奇偶分析】

热门文章

  1. 网站基本安全防护措施有哪些?具体如何实现呢?
  2. android 技术亮点,AndroidQ亮点之一:深色主题
  3. 精品基于Uniapp+SSM实现的记账app家庭账单财务
  4. 数学公式和符号的念法
  5. matlab 高斯序列,如何用MATLAB产生高斯随机序列
  6. LINUX目录——FHS标准
  7. 查找有向图中两个顶点之间是否存在路径
  8. mysql级联删除外键约束_MySQL外键设置 级联删除
  9. 数据结构时间空间复杂度笔记
  10. Python从字符串串中如何提取国家、地区或者城市信息?