转载

使用Swift开发WatchKit(part 1):马上开始

使用Swift开发WatchKit(part 1):马上开始

原文: WatchKit Tutorial with Swift Part 1: Getting Started , 作者: Greg Heo

本文由CocoaChina和 百度智客联盟 共同翻译,译者:反叛中

适用于Xcode 6.3和Swift 1.2!

WatchKit是Apple的新架构,用来开发Apple Watch app,与Xcode 6.2 一起发布。

这个WatchKit教程中,你将使用Swift创建你的第一个WatchKit app。具体地说,你将下载一个比特币价格跟踪app,然后开发一款配套使用的Watch app。

在这个过程中,你将学到如何构建WatchKit app,新的WatchKit UI控件怎样工作以及WatchKit如何布局等等。

那就让我们开始吧!

开始

首先, 下载starter项目 。

打开starter项目,选择iPhone 6模拟器。构建和运行程序,先体验一下。这个程序(编写者:团队成员Mic Pringle)会访问应用程序BitcoinAverage Price Index API,以获得最新的比特币价格,然后显示到屏幕上。

使用Swift开发WatchKit(part 1):马上开始

你是一个比特币亿万富翁吗?

现在轮到我们在手表上跟踪比特币资产了!

在Xcode中,打开File/New/Target…,选择iOS/Apple Watch/Watch App模版

使用Swift开发WatchKit(part 1):马上开始

Watch app是和主iOS app绑定在一起的,工作方式与扩展一样,所以这个选项会为你创建一个单独的target。点击Next继续。

在接下来的窗口中,Xcode会自动填写很多内容,你无需改变比如Product Name这类内容。

使用Swift开发WatchKit(part 1):马上开始

确保语言设置为Swift,不勾选Include Notification Scene和Include Glance Scene。点击Finish,然后Xcode会为Watch界面(interface)创建target和一些starter模版文件,下面你就可以自己编程了!

如果你注意到项目导航面板,你会发现它有两组:

使用Swift开发WatchKit(part 1):马上开始

  1. Watch App仅仅包含故事板(storyboard)和图片…,没有代码!可以把它当做app的"外貌"。

  2. WatchKit Extension包含事件触发后的代码,例如app登录、按键触摸或值改变后要进行的操作。可以把它想象成app的"控制器和模型"。

使用Swift开发WatchKit(part 1):马上开始

我们得到"本地"Watch app后,最好的方式是把Watch当作由扩展控制的另一个更小的屏幕。实际上,模拟器的确是把Watch当作一个额外显示屏幕,下面添加和测试界面对象时你会看到。

注意:Watch app的术语与iOS和Mac app有一些不同--不是视图(view),控件(control)和视图控制器(view controller),而是应该说界面(interface),界面元素(interface object)和界面控制器(interface controller)。

手表界面

设计手表界面时,你可以使用故事板(storyboard)和界面生成器(Interface Builder),就像设计iOS app那样。打开 BitWatch Watch App 组,选择 Interface.storyboard ,你就可以看到手表界面。

使用Swift开发WatchKit(part 1):马上开始

在故事板中你会看到一个空白的界面控制器。现在让我们来添加一些控件!

将一个标签(Label)从对象库(object library)中拖拽到界面上。然后,在它下面再拖拽一个按钮(Button)。

使用Swift开发WatchKit(part 1):马上开始

你可能会注意到一些奇怪的现象--只能改变元素在故事板中的垂直位置(而不是水平位置),元素像被锁定一样,一个接一个地垂直排列。

也就是说,你可以把标签放在按钮上方或按钮放在标签上方,但是你不能像iOS中一样自由地拖动它。遇到这种情况,那些习惯于iOS自动布局(Auto Layout)的人可能会像下面这个家伙一样:

使用Swift开发WatchKit(part 1):马上开始

其实,自动布局不再适用于Apple Watch--它使用自带的系统进行布局和定位。让我们来看一看。

对象定位

WatchKit并不是完全的自动布局,Watch app中的每个界面元素必须"别"到一些东西上,无论是屏幕边缘或是另一个元素,这将决定它的最终位置。

默认情况下,标签和按钮两个元素将出现在屏幕上方;你可以改变它们的顺序,但它们的位置始终相对于屏幕顶部。

在实用功能面板(Utilities panel)的属性查看器(Attributes inspector)中,你可以调整界面元素的位置。选择标签(Label),把水平位置(Horizontal)改成Center,垂直位置(Vertical)保持Top不变。

使用Swift开发WatchKit(part 1):马上开始

下一步,选择按钮(Button),水平位置设为Center,垂直位置设为Bottom。

使用Swift开发WatchKit(part 1):马上开始

从自动布局的观点看,你可以想象成把元素"别"到了顶部和底部的布局参考线中。由于手表的屏幕很小,它的布局就只需要简单地设置两个位置选项--水平和垂直。随着你给界面添加越来越多的元素,你会发现这种相对于其它元素定位的方法是多么简单!

设置格式

我们先设置一些文本,让界面好看些,再来探索属性查看器的其它功能。

选择标签,确保功能面板中的属性查看器处于打开状态。这个标签会显示比特币的价格,所以将标签文本设置为 $0.00 ,选择居中对齐。点击字体(Font)区域的"T"图标,打开字体弹出式菜单,把字体设为System - System, Semibold ,字体大小 30

使用Swift开发WatchKit(part 1):马上开始

选择按钮,把标题(title)设为Refresh。把字体设为 System - System,Medium ,字体大小16。

使用Swift开发WatchKit(part 1):马上开始

这样就好看多了!

使用Swift开发WatchKit(part 1):马上开始

注意:虽然你可以通过代码在运行中改变文本、标题和颜色,但你只能在故事板中改变字体和位置属性。所以如果你以前习惯于在代码中进行布局,你可以多花点时间在Watch app的界面生成器上。

Action和Outlet

Action和outlet的工作方式和你预料的一样,它们允许你通过代码控制界面元素,处理按键等用户操作。

如果仔细想想,你会觉得把界面元素和代码关联在一起有些奇怪,因为故事板在Watch App target中,而代码在WatchKit Extension target中。

这些action和outlet如何跨target,或者说跨设备连接呢?因为app在Watch上,而扩展在手机上!

幸运的是,Apple将在场景后操控,我们不需要担心这些事。

使用Swift开发WatchKit(part 1):马上开始

远程action和outlet?蓝牙的魅力!

Apple会在场景背后以蓝牙方式照顾到WatchKit app和iPhone WatchKit extension之间的所有无线通信。很酷,对不对?

打开辅助编辑器(Assistant editor)确保 InterfaceController.swift 不被遮住。按住Control拖动价格标签到 InterfaceController 类定义下,创建一个outlet,命名为 priceLabel ,点击 Connect

使用Swift开发WatchKit(part 1):马上开始

然后,按住Control将按钮对象拖动到类中。这次,选择Action而不是Outlet,创建一个方法(method)。将这个动作方法(action method)命名为refreshTapped,点击Connect。

界面上的操作就是这些。现在来看看代码。

基本的WatchKit代码

starter项目包含一个叫做BitWatchKit的架构(framework),其中有一些可以获得比特币价格的代码。将这些代码放在一个架构中,就可以方便地被iPhone app和iPhone WatchKit extension使用。

现在要把这个架构添加到你的扩展中。在导航器中打开项目文件,选择 BitWatch WatchKit Extension target,选择 General 选项卡,下翻到 Linked Frameworks and Libraries 区域

使用Swift开发WatchKit(part 1):马上开始

点击架构清单下的+按钮。你会看到一个窗口列出了可添加的架构,其中 BitWatchKit.framework 应该正好显示在列表的最上方。选择它,点击 Add

使用Swift开发WatchKit(part 1):马上开始

既然架构添加好了,你就可以为Watch界面更新一些实时数据了!

切换到 WatchKit Extension groupInterfaceController.swift ,把下面的导入声明(import statement)添加到文件第一行

import BitWatchKit

这将允许你访问定义在架构内的Tracker类。

下一步,把下面两行代码添加到类定义中:

let tracker = Tracker() var updating = false

Tracker实例将用来访问比特币的价格,updating将用来判断是程序否处于更新状态。

把下列辅助方法(helper method)添加到类中:

private func updatePrice(price: NSNumber) {   priceLabel.setText(Tracker.priceFormatter.stringFromNumber(price)) }

这个方法获得参数NSNumber,然后更新Watch上的标签值。Tracker也包含了数字格式化代码,它会把数字例如93.1转换成字符串"$93.10"。

在类中添加另一个辅助方法:

private func update() {   // 1   if !updating {     updating = true     // 2     let originalPrice = tracker.cachedPrice()     // 3     tracker.requestPrice { (price, error) -> () in       // 4       if error == nil {         self.updatePrice(price!)       }       self.updating = false     }   } }

让我们一步步看这些代码:

  1. 首先进行判断,确保你没有在更新。

  2. 保存当前价格,如果价格发生变化则更新UI上显示的价格。

  3. requestPrice()是Tracker类的一个方法,它可以通过网络访问最新的比特币价格。一旦访问你结束,会关闭这个网络连接。

  4. 访问成功后,就通过updatePrice()更新标签。

现在要做的是调用这些方法,让屏幕显示真正的数据。

界面生命周期

你最早可以在 awakeWithContext(_:) 中设置界面元素。这时候,界面已全部载入,action和outlet也已经连接。

这意味着你可以设置界面对象和显示数据,但是,界面不一定可见!所以这时候应该把对象调整到一个理想的状态,但也不必进行访问网络等昂贵的操作。

把下面的代码添加到 awakeWithContext 末尾:

updatePrice(tracker.cachedPrice())

如果存在前一次存储的值,它会用之前的值更新价格标签。值存储在tracker中,访问本地数据成本很低。

将下面代码添加到 willActivate() 末尾:

update()

willActivate就像iOS中的 viewWillAppear ,意味着界面将被激活并显示到Watch上。这是更新数据的好时期,所以可以在这里调用update(),开始网络请求,更新标签。

最后,把相同的代码添加到 refreshTapped

update()

当使用者点击Refresh,会产生相同的效果:调用update(),更新数据。

测试你的App

为了测试你的Watch app,你需要将Watch作为 额外的显示屏 。如果iOS Simulator app正在运行,切换过去。如果没有,构建和运行app,停止后回到iOS Simulator。打开菜单 Hardware/External Displays ,勾选一个AppWatch选项。

使用Swift开发WatchKit(part 1):马上开始

你现在应该有两个模拟器窗口--一个显示iPhone,另一个显示Watch界面。

回到Xcode,在工具栏中选择 BitWatch Watch App 方案,并选择iPhone 6 Simulator。

使用Swift开发WatchKit(part 1):马上开始

构建运行,转到模拟器,你就会看到比特币数据显示在你的Apple Watch上!

使用Swift开发WatchKit(part 1):马上开始

关于界面的更多信息

既然基本的设置已经到位,现在来看看有什么需要完善的地方。

还有两项功能需要在Watch上实现:

  • 最近更新时间

  • 指示价格增减的上/下箭头

要实现这两项功能,首先要将相应的图片添加到资源目录(asset catalog)中。打开BitWatch Watch App组中的Images.xcassets。注意:项目文件中有三个Images.xcassets文件,确保你选择正确的组!

starter项目中包含两个图片文件:Down@2x.png 和 Up@2x.png。将这两个文件拖到图片列表中。

使用Swift开发WatchKit(part 1):马上开始

注意图片名称只包含了@2x后缀。在WatchKit你只需要使用@2x图片,因为所有的Apple Watch都是Retina。

再次打开Interface.storyboard回到布局界面。

拖到另一个标签到界面,放置在Refresh按钮上方。文本设置为Last Updated,文本样式Subhead,文本对齐方式居中。

再设置标签位置,水平位置Center,垂直位置Bottom。

使用Swift开发WatchKit(part 1):马上开始

你可能会有疑问:如果Refresh按钮和Last Updated标签位置都设置为Bottom,Watch怎么辨别他们排列的位置呢?

在iOS,文档大纲里的顺序决定视图的z轴,或者说,谁在谁的"上方"或"后面"。对于Watch界面,界面元素并不相互重叠,所以我们不需要关注具体的z轴位置。文档大纲里的顺序将决定垂直方向对象从上至下的排列顺序(结合垂直方向的对齐设置)

使用Swift开发WatchKit(part 1):马上开始

为进一步理解上面的话,对调Refresh和Last Updated对象在大纲中的位置--你会看到它们也在界面生成器上对调了。试过之后,请把它们调回来。

组对象(Group)

现在,在你的Watch界面上,界面对象一个叠一个。如何把对象并排放置呢?

另一个可供你使用的对象是组。组类似于容器,你可以把界面对象放在里面。但是,它们同样也有水平和垂直方向上的位置设置。你可以在组里嵌套另一个组,实现各种各样的布局!

注意:组也是界面元素,有背景颜色和图片属性。在这个app中,组被设置为不可见,当然,我们仍能看到他对布局的作用。

下面是iPhone app中价格上升/下降的指示标志:

使用Swift开发WatchKit(part 1):马上开始

总体上就是在标签旁边放置一个箭头图片。

把一个组从对象库拖到故事板上,放置在价格标签和Last Updated标签之间。在属性查看器中,确保组的布局设置(Layout setting)为Horizontal。

使用Swift开发WatchKit(part 1):马上开始

然后,从对象库中拖拽一个图片对象放在组中,再拖拽一个标签放在组中图片的右边。

使用Swift开发WatchKit(part 1):马上开始

现在,你有两个对象并排放置,接下来我们将设置它们在组内的位置和大小。

位置和大小

选择标签,水平和垂直位置改成Center。对图片也进行同样的设置。

由于图片和标签在组内,它们是相对于组居中,而不是相对于外部的故事板。这意味着,组的位置改变或者尺寸改变,图片和标签仍然会在组内居中。

默认情况下,大多数的界面对象的尺寸设置为Size to Fit Content。这同样适用于标签,因为标签的文本可能发生变化。但是,箭头的大小是固定的,所以你可以在故事板中设置固定的尺寸。这样,Watch就不会在运行过程中还来计算图片的尺寸了。

选择图片,在属性查看器中找到Size。将Width设置为Fixed Width,Height设置为Fixed Height。宽度和高度都设为32。

使用Swift开发WatchKit(part 1):马上开始

最后的界面设置

由于标签的文本不会改变,你可以在故事板里把标签文本设置为1 BTC。

图片决定于比特币价格的前值,所以需要创建一个outlet。打开辅助编辑器,按住Control,拖动图片对象到类定义中。将outlet命名为image,单击Connect。

你还需要为Last Updated标签设置一个outlet。按住Control将标签拖动到类定义,将outlet命名为lastUpdatedLabel,单击Connect。

这就是Watch的界面--在你追踪比特币资产之前,还有一些利用代码更新界面的方法和窍门。

最后的代码编写

打开 InterfaceController.swift ,有两个新的对象要处理:Last Updated标签和图片

在类中添加下列辅助方法:

private func updateDate(date: NSDate) {   self.lastUpdatedLabel.setText("Last updated /(Tracker.dateFormatter.stringFromDate(date))") }

这个方法更新last updated标签,与更新价格标签的方法类似。同样,Tracker能将日期格式化,显示时间。

再将下面的辅助方法添加到类中:

private func updateImage(originalPrice: NSNumber, newPrice: NSNumber) {   if originalPrice.isEqualToNumber(newPrice) {     // 1     image.setHidden(true)   } else {     // 2     if newPrice.doubleValue > originalPrice.doubleValue {       image.setImageNamed("Up")     } else {       image.setImageNamed("Down")     }     image.setHidden(false)   } }

这个方法会对比原始的价格和新价格。

  1. 如果这两个价格相等,隐藏箭头图标。

  2. 如果价格不一样,根据价格的变化,设置上/下箭头。使图片可视化。

调用setHidden会使对象重新布局。还记得你设置了图片和1 BTC标签相对于组位置居中吗?当隐藏图片时,标签左边会留出额外的空间。但是界面会重新布局,移动标签位置,使标签在组内居中。

注意:如果需要在隐藏对象的同时使它"占有空间",可以用setAlpha将对象的alpha设为0。

既然所有的辅助方法都已放置到位,接下来你需要调用它们。在awakeWithContext最后添加下列代码:

image.setHidden(true) updateDate(tracker.cachedDate())

由于登陆时你没有以前的价格信息,箭头图片处于隐藏状态。价格直接来自缓存,你也可以从缓存中获得日期。

找到update(),将下面代码添加到最里层的if程序块,if error==nil { :

self.updateDate(NSDate()) self.updateImage(originalPrice, newPrice: price!)

updateDate会更新last update标签,显示最近更新时间。updateImage会更新上/下箭头。

构建和运行Watch app,结果如下图

使用Swift开发WatchKit(part 1):马上开始

你可以看到价格和前面显示的一样。由于前面运行过一次app,所以有缓存的价格。如果现在的价格和缓存的价格不一样,你应该会看到上/下箭头。

数据源每分钟更新一次,所以你可以等一分钟,然后点击Refresh按钮获得最新的比特币价格。现在,你的比特币资产是否足够支付土豪金版Apple Watch呢?

下一步路在何方?

这里是上述教程的 最终的项目文件 。

祝贺--你现在了解了创建WatchKit app的基础知识!

但是仍然还有很多要学--包括其它的界面对象、导航和切换。记住这只是WatchKit app中的一种--你还可以制作Glance(与Today extension类似),或Custom Actionable Push Notifications。

更多内容,请访问我们的 WatchKit视频教程系列 ,或查看我们的 WatchKit书籍 。

同时,希望您通过留言和我们分享自己的WatchKit冒险。

正文到此结束
Loading...