开始学习 WatchKit!
更新于2015年1月19日:经过了Xcode 6.2 Beta版的测试; 没有项目/代码更改需要。 记住要使用苹果最新的测试版!
iOS开发者欢欣鼓舞 - WatchKit终于来了!
WatchKit是苹果伴随着的Xcode 6.2测试版发布的、用于创建Apple Watch应用程序的新框架和相关技术的开发包。
在这个WatchKit教程中,您将使用 Swift 创建第一个WatchKit应用程序。 具体来说,您将开发一个比特币价格跟踪应用程序,同时创建一个与之一同使用的 Watch 应用程序。
在这个过程中,您将学习了解如何架构WatchKit应用程序,怎么让一些新WatchKit特有的UI控件工作起来,WatchKit布局,等等。
让我们开始吧! ┗(°0°)┛
注:由于Apple Watch SDK文档是向公众开放的,我们还没有听到任何矛盾的规定,我们假设现在聊WatchKit是合适的。 如果有人听到对此事的官方消息,请告诉我们!
入门
首先, 下载本WatchKit教程的起始项目,下载地址:
http://cdn2.raywenderlich.com/wp-content/uploads/2014/11/BitWatch-Starter.zip
打开起始项目,然后选择iPhone 6模拟器作为运行目标。 构建和运行应用程序来感受一下吧。 该应用程序使用Bitcoin 平均价格指数 API来获取最新的比特币的价格并在屏幕上显示出来。
你是一个Bitcoin的亿万富翁吗?
现在是时候开始在Watch上跟踪你的比特币的财富了!
在Xcode中,定位到File\New\Target…并选择了iOS\Apple Watch\Watch App应用程序模板。
一个Watch应用程序可以同主体iOS捆绑在一起,像扩展一样工作。但这个选项将创建一个单独的target。 单击Next继续。
在下面的屏幕中,Xcode将自动填充许多的值,有些值无法改变,比如产品名称。
确保语言设置为Swift,并且Include Notification Scene 和Include Glance Scene选项都不要被选中。 单击Finish,Xcode中会设置target和一些Watch界面的基本模板文件,随时等待您上手开发!
如果你看一下项目导航器,你会看到有两个不同的分组:
Watch分组
- Watch应用程序分组包含只是storyboard and image assets…并没有代码!可以认为是您的应用程序的“视图”。
- 该WatchKit Extension包含一些事件代码,这些代码在像应用程序启动、按钮轻击,或switch变化这类事件中事件执行。 可以认为这是您的应用程序的“控制器和模型”。
WatchKit_03
直到我们能够接触“Native”的Watch应用之前,最好把这种设定方式认定为:Watch是从扩展控制的第二个较小的屏幕。 事实上,模拟器把Watch只是当一个外接显示器,可以看到开始添加和测试界面对象。
注:Watch应用程序的术语跟iOS和Mac应用程序略有不同,不是视图、控制器和视图控制器,而是有界面,界面对象和界面控制器。
Watch界面
当设计你的Watch应用程序界面时,您可以使用Storyboard和Interface Builder,就像你的iOS应用程序一样。 看这里,打开BitWatch Watch应用程序组,并选择Interface.storyboard。
Watch storyboard1
你会看到在故事板中看到一个空的界面控制器。 让我们添加一些控件吧!
开始从对象库拖动Label到界面上。 然后,在其下放一个按钮。
手表storyboard2
您可能会在这里注意到有一些奇怪的地方 - 你可以在故事板周围拖动界面元素,但只能垂直(不是水平)地改变自己的位置,并一个一个叠加地垂直锁定控件。
换句话说,你可以把标签放在按钮上,或者把按钮放在标签上,但是你不能,像你可以在iOS上一样“随意地”拖动元素。 习惯使用在iOS使用自动布局的你可能会做出如下这幅表情:
ConfusedGuy
原来,在Apple Watch上并没有自动布局,它在布局和定位上有自己的机制。 让我们一起来看看。
定位
这不是很像自动布局,但在你的Watch应用程序中,每一个界面元素都必须“固定”到某些东西上,不管是屏幕边缘或其他对象。 这将决定其最终的位置。
默认情况下,两个对象被定位在顶部; 可以改变它们的顺序,让其中一个在另一个的顶上,但是它们的位置将相对于屏幕的顶部放置。
你可以使用 Utilities 面板中的Attributes inspector来调整界面元素的位置。 选择标签并改变其Horizontal位置属性为Center ,让Vertical位置属性为Top。
Watch center top
接下来,选择按钮,改变其Horizontal位置属性为Center ,其Vertical位置属性为Bottom 。
Watch storyboard3
如果用自动布局术语来描述的话,你可以认为这是将界面元素固定到布局的顶部和底部。 由于Watch的屏幕是如此小,所以它简单到只是选择两个位置来进行调节 - 水平和垂直。 你会看到它是多么容易地相对彼此来对自己进行位置定位。在后面,你可以添加更多的东西到界面上。
格式化
首先,让我们设置一些文本和格式来使用界面看起来漂亮一些,并探讨一些在Attributes inspector中的使用的其他选项。
选择标签,并确保在Utilities中的Attributes inspector处于打开状态。 该标签将显示Bitcoin的价格,所以设置文本为 $ 0.00,选择居中对齐。 通过单击字体域的“T”图标,打开字体弹出块,并设置值为Custom, Avenir Next, Demi Bold, 尺寸为 30。
Watch 标签字体
选择按钮,改变其标题为Refresh 。 更改其字体为Custom, Avenir Next, Medium, 尺寸16。
手表按钮
这看起来很不错!
手表storyboard4
请注意,您可以在运行时通过代码来改变如文本、标题和颜色这类属性,但你只可以在故事板中修改字体和定位属性。 所以,如果你已经习惯了在代码中设置您的布局的话。相比开发 iOS 应用程序,开发 Watch 应用程序需要你多花一点时间在Interface Builder上。
注:又一个友好的提醒,WatchKit是β版状态 -因此有可能苹果在将来某个时候将可以在代码中开放界面对象的更多方法和属性。
Action 和 Outlet
Action 和 Outlet的工作就像你所期望的那样,让您从代码中访问界面元素和处理用户动作,如按键。
如果你觉得麻烦了,把这些东西关联起来有点奇怪,因为故事板在Watch App target 中,而代码则在WatchKit Extension target 中。
怎么能跨 target 关联Action 和Outlet 呢? 甚至能跨设备关联呢?因为应用程序是在Watch 上,而扩展在手机上!
幸运的是,这神奇的一部分是苹果在后台处理好了的,所以你不必担心。
远程Action和Outlet? 蓝牙魔法!
在幕后,苹果公司负责所有在您WatchKit应用程序 和 iPhone WatchKit扩展之间的无线通信,使用了蓝牙技术。 很酷,不是吗?
打开Assistant编辑器,并确保InterfaceController.swift打开。按下Ctrl键,从价格标签拖动到InterfaceController类里面,来定义创建一个Outlet,把它叫做priceLabel,然后单击Connect 。
Watch Outlet
接下来,按住Ctrl,从按钮拖动到类里。 这一次,一定要选择Action来创建一个方法,而不是Outlet。 将操作方法命名refreshTapped,然后单击Connect 。
这就是到目前为止的界面。 现在是时候切换到代码,并得到了一些数据显示出来了!
基本的WatchKit代码
起始项目包括一个名为BitWatchKit的框架,包含一些自定义代码来获取比特币的价格。我们把这个代码做在框架里,因此它可以同时在iPhone应用程序中使用,在iPhone WatchKit扩展中也可以很容易地使用。
将这个框架添加到您的扩展中,打开导航器中的项目文件,并选择BitWatch WatchKit扩展的target。选择General选项卡,然后向下滚动到Linked Frameworks and Libraries部分。
Watch扩展
点击框架列表下的+按钮。你会看到一个窗口,其中列出了可用来添加的框架,你应该看到BitWatchKit.framework就在列表的顶部。选择它,然后单击添加。
Watch框架
现在,框架添加进来了,你可以用一些真实的数据更新您的Watch界面!
切换到InterfaceController.swift的WatchKit Extension组。 将以下import语句添加到文件的顶部:
import BitWatchKit
这将允许您访问框架中定义的Tracker类。
接下来,在类定义中添加以下属性:
let tracker = Tracker()
var updating =false
你需要使用Tracker 实例来通过网络获得比特币价格。您将使用updating变理来标识,是否有一个挂着的“更新价格”的请求。
添加下面的辅助方法到类中:
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被连接起来。
这意味着你可以设置界面对象,并开始显示数据。然而,到目前为止该界面还不必要放到Watch上去!因为重要的是使事情达到一个合理的状态:你可能不希望进行昂贵的操作,如进行网络调用。
将以下内容添加到awakeWithContext 结尾处:
updatePrice(tracker.cachedPrice())
这将使用先前缓存值(如果存在的话)更新价格标签。因为这个值是由被Tracker 所缓存的,它是本地数据,获取起来代价很小。
以下内容添加到willActivate() 的尾部
update()
willActivate就像iOS 中的viewWillAppear。并且意味着界面即将激活,并出现在Watch中。这是一个很好的刷新数据的信号,因此在这里调用update() ,以开始网络请求,并且更新标签。
最后,将相同的代码行添加到refreshTapped :
update()
当用户点击Refresh,你想要同样的事情发生:调用update() ,并显示一些新的数据。
测试您的应用程序
要测试你的Watch应用程序,你需要让Watch作为外部显示器。 如果你的iPhone模拟器有应用在运行,切换到它。 否则,构建和运行应用程序,在Xcode把它停掉,然后再切换回iOS模拟器。在菜单中,导航到Hardware\External Displays,并选择一个Apple Watch选项。
Watch模拟器
你应该现在有两个模拟器窗口 - 一个显示了iPhone,一个是Watch所用的。
返回到Xcode中,选择工具栏中的BitWatch Watch App 方案,并选择iPhone 6模拟器。
Watch方案
构建并运行,然后切换到模拟器。你应该在苹果Watch 看到Bitcoin的数据!
手表APP1
更多的界面
现在,您已经基本入门了,现在来看看你可以使用界面来做的更多的东西。
在本应用中,还有两个你想要在Watch 上实现的元素:
- 最后更新时间
- 向上/向下图像,以显示价格是否增加或减少
要做到这一点,你首先需要将图像添加到asset目录。打开BitWatch Watch App组的Images.xcassets。这里要小心:在项目中,有 3个 Images.xcassets文件,所以一定要确保你在正确的组!
起始项目包括两个图像文件:[email protected]和[email protected]。从finder窗口,拖动这两个文件到图像集合列表中。
看asset
注意,图像唯一的@2x的变体也包括在内。在WatchKit 中你只需要@2x 的图像– 因为没有非Retina屏的Apple Watch!
接下来,再次打开Interface.storyboard,返回到布局。
将另一个标签拽到界面上,并把它放到Reresh按钮上面。设置标签文本为Last Updated ,并且将字体设置为Custom, Avenir Next, Regular, 和尺寸 13。也改变文本对齐方式为Center。
对定位的设置,改变Horizontal位置属性设置为Center和Vertical位置属性设置为Bottom。
手表storyboard5
你可能会想:如果Refresh按钮、这个新标签的定位属性均设置为底部,Watch是知道如何,用什么样的顺序来放置他们?
在iOS上,在文档大纲中,视图顺序确定了z-order,或者确定了哪个视图“在顶部”或在别的视图“后面”。而针对Watch界面,界面元素不重叠,所以没有必要跟踪z-order。相反,在文档概要中的顺序反映了垂直的从顶部至底部的顺序(结合垂直对齐设置)。
Watch 外观
要明白我的意思,在大纲中交换Refresh和Last Updated控件的顺序- 你会看到它们在Interface Builder中直观地交换好了。当你完成时,再换回来
分组
到目前为止,你的Watch 界面包括堆积在彼此顶部的界面对象。那么,我们如何一个个并排对象呢?
供您使用的另一个对象是组 。组就像容器,你可以把界面对象放在他们里面。 然而,它们也具有是否应该水平或垂直地布置它们所包含元素的设置。你可以通过在组中嵌套组,使用不同布局来获得各种不同的界面放置!
注:组可以是有背景颜色和图片的界面元素。在这个应用程序中,除了它们是如何对布局做贡献之外,对用户是不可见的(译者注:因为本应用中的组,没有背景颜色和图片,所以不可见)!
下面是看起来像在iPhone应用程序中的价格上升/下降的指示器:
Watch app剪头
所以,总体规划是在标签旁边放置一个图片。
将一个新组从对象库拖动到故事板中,并把它放在price标签和last updated标签之间。在Attributes inspector中,确保组的布局设置为Horizontal 。
手表storyboard6
接下来,将一个图片控件从对象库拖动到组控件里面。然后把一个新的标签拖动到组中,并将其放置在图像的右侧。
Watch storyboard7
这样就有两个对象并排在一起,但现在问题是,如何设置它们的位置和大小。
位置和大小
选择标签并同时改变其Horizontal和Vertical 位置属性为Center 。对图片控件做相同的操作。
由于图像和标签是一个组内,它们在组中居中,而没有在外部故事板作为一个整体的对象中。这意味着,组四处移动,以及因为某种原因被调整尺寸,图像和标签都会停留在组的正中心。
默认情况下,大多数界面对象都可将其size属性设置为Size to Fit Content。这非常适用于标签,因为文本可能会改变。然而,箭头图片是在资源包中的,并且有一个已知大小,你可以在故事板中设置大小。这意味着Watch在后面将不需要计算尺寸。
选择图像,并且在Attributes inspector中找到Size部分。更改Width设置为Fixed Width 和高度设置为 Fixed Height。同时设置width和height值为32。
手表大小
集成界面
如果只是把标签放到故事板中,标签的文本不会改变。改变其文本为 1BTC,并且将其字符修改为:Custom, Avenir Next, Regular, 和尺寸 13。
此图像将根据先前比特币的价格而改变(译者注:以前价格比当前价格低还是高),因此你需要一个outlet。打开辅助编辑器,按下Ctrl键,从图像拖动到类定义中。命名为image outlet ,然后单击Connect 。
对于“Last Updated”标签,你需要另外一个 outlet 。按下Ctrl键,从标签拖动到类定义,并命名为lastUpdatedLabel,然后单击Connect 。
这就是它的所有界面– 在开始跟踪你的Bitcoin 资产前。如果从代码更新布局,需要更多一些的代码和一些技巧。
集成代码
打开InterfaceController.swift。 有两个新的事情要处理:“lastupdated”标签和图像。
添加下面的辅助方法到类中:
private func updateDate(date:NSDate)
{
self.lastUpdatedLabel.setText("Last updated \(Tracker.dateFormatter.stringFromDate(date))")
}
此方法像 price标签更新一样,更新last updated 标签。同样,Tracker具有格式化器对象,在这种情况下,将格式化日期,以只显示时间。
增加一个辅助方法到类中:
privatefunc 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!)
这将更新 last updated标签来显示当前时间。在这里,也同时得到先前的价格和新价格,然后如果价格发生了变化可以使用updateImage显示向上或向下箭头的图像。
构建和运行监视应用程序看看模拟器。
你应该看到当前价格跟之前一样显示。 因为你已运行一次应用程序,应该已经有了一个缓存价格,如果缓存价格与当前价格不同,你应该看到一个向上或向下箭头了。
源数据每分钟更新一次,这样你就可以等待一分钟,然后点击Refresh按钮,获得最新的比特币的价格。你能负担得起的纯金Apple Watch版本了吗?]
下面如何开始?
这里是上面WatchKit教程的最后一个示例项目。下载地址:
http://cdn1.raywenderlich.com/wp-content/uploads/2014/11/BitWatch-Final-1.2.zip
恭喜你 - 你现在知道制作WatchKit应用程序的基础知识了!
但是,还有很多东西要学 -包括额外的界面对象,导航和切换传递(指Hand Off)。并记住,这仅仅是学习了一种类型的应用程序WatchKit的制作 - 你也可以制作Glances(类似于Today扩展),或自定义可操作的推送通知等。
译者:优才网
作者:Greg Heo
原文:http://www.raywenderlich.com/89562/watchkit-tutorial-with-swift-getting-started