Apple Watch应用开发 2
转自http://onevcat.com/2014/11/watch-kit/发现一个写的非常好的人,转一下 以后持续关注
主要类
WKInterfaceController 和生命周期
WKInterfaceController
是 WatchKit 中的 UIViewController
一样的存在,也会是开发 Watch App 时花时间最多的类。每个 WKInterfaceController
或者其子类应该对应手表上的一个整屏内容。但是需要记住整个 WatchKit 是独立于 UIKit 而存在的,WKInterfaceController
是一个直接继承自 NSObject
的类,并没有像 UIKit
中 UIResponser
那样的对用户交互的响应功能和完备的回调。
不仅在功能上相对 UIViewController
简单很多,在生命周期上也进行了大幅简化。每个 WKInterfaceController
对象必然会被调用的生命周期方法有三个,分别是该对象被初始化时的 -initWithContext:
,将要呈现时的 -willActivate
以及呈现结束后的 -didDeactivate
。同样类比 UIViewController
的话,可以将它们理解为分别对应 -viewDidLoad
,viewWillAppear:
以及 -viewDidDisappear:
。虽然看方法名和实际使用上可能你会认为 -initWithContext:
应该对应 UIViewController
的 init
或者 initWithCoder:
这样的方法,但是事实上在 -initWithContext:
时 WKInterfaceController
中的“视图元素” (请注意这里我加上了引号,因为它们不是真正的视图,稍后会再说明) 都已经初始化完毕可用,这其实和 -viewDidLoad
中的行为更加相似。
我们一般在 -initWithContext:
和 -willActivate
中配置“视图元素”的属性,在 -didDeactivate
中停用像是 NSTimer
之类的会 hold 住 self
的对象。需要特别注意的是,在 -didDeactivate
中对“视图元素”属性进行设置是无效的,因为当前的 WKInterfaceController
已经非活跃。
WKInterfaceObject 及其子类
WKInterfaceObject
负责具体的界面元素设置,包括像是 WKInterfaceButton
,WKInterfaceLabel
或 WKInterfaceImage
这类物件,也就是我们上面所提到的“视图元素”。可能一开始会产生错觉,觉得 WKInterfaceObject
应该对应 UIView
,但其实上并非如此。WKInterfaceObject
只是 WatchKit 的实际的 View 的一个在 Watch Extension 端的代理,而非 View 本身。Watch App 中实际展现和渲染在屏幕上的 view 对于代码来说是非直接可见的,我们只能在 Extension target 中通过对应的代理对象对属性进行设置,然后在每个 run loop 需要刷新 UI 时由 WatchKit 将新的属性值从手机中传递给手表中的 Watch App 并进行界面刷新。
反过来,手表中的实际的 view 想要将用户交互事件传递给 iPhone 也需要通过 WKInterfaceObject
代理进行。每个可交互的 WKInterfaceObject
子类都对应了一个 action,比如 button 对应点击事件,switch 对应开或者关的状态,slider 对应一个浮点数值表明选取值等等。关联这些事件也很简单,直接从 StoryBoard 文件中 Ctrl 拖拽到实现中就能生成对应的事件了。虽然 UI 资源文件和代码实现是在不同的 target 中的,但是在 Xcode 中的协作已然天衣无缝。
Watch App 采取的布局方式和 iOS app 完全不同。你无法自由指定某个视图的具体坐标,当然也不能使用像 AutoLayout 或者 Size Classes 这样的灵活的界面布局方案。WatchKit 提供的布局可能性和灵活性相对较小,你只能在以“行”为基本单位的同时通过 group 来在行内进行“列”布局。这带来了相对简单的布局实现,当然,同时也是对界面交互的设计的一种挑战。
另外值得一提的是,随着 WatchKit 的出现及其开发方式的转变,代码写 UI 还是使用 StoryBoard 这个争论了多年的话题可以暂时落下帷幕了。针对 Watch 的开发不能使用代码的方式。首先,所有的 WKInterfaceObject
对象都必须要设计的时候经由 StoryBoard 进行添加,运行时我们无法再向界面上添加或者移除元素 (如果有移除需要的,可以使用隐藏);其次 WKInterfaceObject
与布局相关的某些属性,比如行高行数等,不能够在运行时进行变更和设定。基本来说在运行时我们只能够改变视图的内容,以及通过隐藏某些视图元素来达到有限地改变布局 (其他视图元素会试图填充被隐藏的元素)。
Table 和 Context Menu
大部分 WKInterfaceObject
子类都很直接简单,但是有两个我想要单独说一说,那就是 WKInterfaceTable
和 WKInterfaceMenu
。UITableView
大家都很熟悉了,在 WatchKit 中的 WKInterfaceTable
虽然也是用来展示一组数据,但是因为 WatchKit API 的数据传输的特点,使用上相较 UITableView
有很大不同和简化。首先不存在 DataSource 和 Delegate,WKInterfaceTable
中需要呈现的数据数量直接由其实例方法 -setNumberOfRows:withRowType:
进行设定。在进行设定后,使用 -rowControllerAtIndex:
枚举所有的 rowController
进行设定。这里的 rowController
是在 StoryBoard 中所设定的相当于 UITableViewCell
的东西,只不过和其他 WKInterfaceObject
一样,它是直接继承自 NSObject
的。你可以通过自定义 rowController
并连接 StoryBoard 的元素,并在取得 rowController
对其进行设定,即可完成 table 的显示。代码大概是这样的:
// MyRowController.swift import Foundation import WatchKitclass MyRowController: NSObject { @IBOutlet weak var label: WKInterfaceLabel! }// InterfaceController.swift import WatchKit import Foundationclass InterfaceController: WKInterfaceController {@IBOutlet weak var table: WKInterfaceTable!let data = ["Index 0","Index 1","Index 2"]override init(context: AnyObject?) {// Initialize variables here. super.init(context: context)// Configure interface objects here.NSLog("%@ init", self)// 注意需要在 StoryBoard 中设置 myRowControllerType// 类似 cell 的 reuse idtable.setNumberOfRows(data.count, withRowType: "myRowControllerType")for (i, value) in enumerate(data) {if let rowController = table.rowControllerAtIndex(i) as? MyRowController {rowController.label.setText(value)}}} }
对于点击事件,并没有一个实际的 delegate 存在,而是类似于其他 WKInterfaceObject
那样通过 action 将点击了哪个 row 作为参数发送回 WKInterfaceController
进行处理。
另一个比较好玩的是 Context Menu,这是 WatchKit 独有的交互,在 iOS 中并不存在。在任意一个 WKInterfaceController
界面中,长按手表屏幕,如果当前 WKInterfaceController
中存在上下文菜单的话,就会尝试呼出找这个界面对应的 Context Menu。这个菜单最多可以提供四个按钮,用来针对当前环境向用户征询操作。因为手表屏幕有限,在信息显示的同时再放一些交互按钮是挺不现实的一件事情, 也会很丑。而上下文菜单很好地解决了这个问题,相信长按呼出交互菜单这个操作会成为今后 Watch App 的一个很标准的交互操作。
添加 Context Menu 非常简单,在 StoryBoard 里向 WKInterfaceController
中添加一个 Menu,并在这个 Menu 里添加对应的 MenuItem 就行了。在 WKInterfaceController
我们也有对应的 API 来在运行时根据上下文环境进行 MenuItem 的添加 (这是少数几个允许我们在运行时添加元素的方法之一)。
-addMenuItemWithItemIcon:title:action:
-addMenuItemWithImageNamed:title:action: -addMenuItemWithImage:title:action: -clearAllMenuItems
但是 Menu 和 MenuItem 对应的类 WKInterfaceMenu
和 WKInterfaceMenuItem
我们是没有办法拿到的。没错,它们甚至都没有存在于文档里 :(
基础导航
WKInterfaceController
的内建的导航关系基本上分为三类。首先是像 UINavigationController
控制的类似栈的导航方式。相关的 API 有 -pushControllerWithName:context:
,-popController
以及 -popToRootController
。后两个我想不必太多解释,对于第一个方法,我们需要使用目标 controller 的 Identifier
字符串 (没有你只能在 StoryBoard 里进行设置) 进行创建。context
参数也会被传递到目标 controller 的 -initWithContext:
中,所以你可以以此来在 controller 中进行数据传递。
另一种是我们大家熟悉的 modal 形式,对应 API 是 -presentControllerWithName:context:
和 -dismissController
。对于这种导航,和 UIKit
中的不同之处就是在目标 controller 中会默认在左上角加上一个 Cancel 按钮,点击的话会直接关闭被 present 的 controller。我只想说 Apple 终于想通了,每个 modal 出来的 controller 都是需要关闭的这个事实...
最后一种导航方式是类似 UIPageController
的分页式导航。在 iOS app 中,在应用第一次开始时的教学模块中这种导航方式非常常见,而在 WatchKit 里可以说得到了发扬光大。事实上我个人也认为这会是 WatchKit 里最符合使用习惯的导航方式。在 WatchKit 上的 page 导航可能会和 iOS app 的 Tab 导航所提供的功能相对应。
在实现上,page 导航需要在 StoryBoard 中用 segue 的方式将不同 page 进行连接,新添加的 next page
segue 就是干这个的:
另外 modal 导航的另一个 API -presentControllerWithNames:contexts:
接受复数个的 names
和 context
,通过这种方式 modal 呼出的复数个 Controller 也将以 page 导航方式呈现。
当然,作为 StoryBoard 的经典使用方式,modal 和 push 的导航方式也是可以在 StoryBoard 中通过 segue 来实现的。同时 WatchKit 也为 segue 的方式提供了必要的 API。
一些界面实践
因为整个架构和 UIKit
完全不同,所以很多之前的实践是无法直接搬到 WatchKit App 中的。
图像处理
在 UIKit
中我们显示图片一般使用 UIImageView
,然后为其 image
属性设置一个创建好的 UIImage
对象。而对于 WatchKit 来说,最佳实践是将图片存放在 Watch App 的 target 中 (也就是 StoryBoard 的那个 target),在对 WKInterfaceImage
进行图像设置时,尽量使用它的 -setImageNamed:
方法。这个方法将只会把图像名字通过手机传递到手表,然后由手表在自己的 bundle 中寻找图片并加载,是最快的途径。注意我们的代码是运行在于手表的 Watch App 不同的设备上的,虽然我们也可以先通过 UIImage
的相关方法生成 UIImage
对象,然后再用 -setImage:
或者 -setImageData:
来设置手表上的图片,但是这样的话我们就需要将图片放到 Extension 的 target 中,并且需要将图片的数据通过蓝牙传到手表,一般来说这会造成不可忽视的延迟,会很影响体验。
如果对于某些情况下,我们只能在 Extension 的 target 中获得图片 (比如从网络下载或者代码动态生成等),并且需要重复使用的话,最好用 WKInterfaceDevice
的 -addCachedImage:name:
方法将其缓存到手表中。这样,当我们之后再使用这张图片的时候就可以直接通过 -setImageNamed:
来快速地从手表上生成并使用了。每个 app 的 cache 的尺寸大约是 20M,超过的话 WatchKit 将会从最老的数据开始删除,以腾出空间存储新的数据。
动画
因为无法拿到实际的视图元素,只有 WKInterfaceObject
这样的代理对象,以及布局系统的限制,所以复杂的动画,尤其是 UIView
系列或者是 CALayer
系列的动画是无法实现的。现在看来唯一可行的是帧动画,通过为 WKInterfaceImage
设置包含多个 image 的图像,或者是通过计时器定时替换图像的话,可以实现帧动画。虽然 Apple 自己的例子也通过这种方法实现了动画,但是对于设备的存储空间和能耗都可能会是挑战,还需要实际拿到设备以后进行实验和观察。
其他 Cocoa Touch 框架的使用
Apple 建议最好不要使用那些需要 prompt 用户许可的特性,比如 CoreLocation 定位等。因为实际的代码是在手机上运行的,这类许可也会在手机上弹出,但是用户并不一定正好在看手机,所以很可能造成体验下降。另外大部分后台运行权限也是不建议的。
对于要获取这些数据和权限,Apple 建议还是在 iOS app 中完成,并通过 App Groups 进行数据共享,从而在 Watch Extension 中拿到这些数据。
转载于:https://www.cnblogs.com/lxllanou/p/4427779.html
Apple Watch应用开发 2相关推荐
- 回复 集赞 抢 《Apple Watch 苹果开发教程》活动开始了!!!
"回复 集赞" 抢 <Apple Watch 苹果开发教程>活动开始了!!! 鸣谢:特别感谢CSND一直以来的支持和关爱!! 活动方式: 回复积赞 第1步:回复该帖 ...
- apple iOS订阅开发-服务端
前言 开发苹果订阅,客户端的改动不大,主要服务端要处理苹果服务器发送的通知,判断通知类型,验证收据 基本步骤 1.苹果后台创建订阅商品,创建共享密钥password 2.苹果后台配置通知自己服务器地址 ...
- 读来自APple的ioS开发指南
基本申明:需要安装在Inter-based macintosh计算机上,进行开发 Development of iOS apps requires an Intel-based Macintosh c ...
- Apple watch 开发指南(2) 前言
第一篇 前言 这是一个初级的api或者说是技术文档.苹果公司提供这些信息来帮助你规划需要采用的技术和使用苹果品牌产品需要的编程接口. 本文档提供的信息有可能改变,根据本文档实现的软件需要在最终发行 ...
- Apple watch 开发指南(1) 预览
答应大家,开始翻译 Apple watch的开发指南今天开始, 首先先览为快,给大家看一下目录~ 转载请注明:http://www.techfoxbbs ...
- 如何在 Apple Silicon (M1) 上开发 Teams App
apple 在几个月前发布了自家的芯片 M1,由于将多核cpu,多核gpu,神经网络运算,内存和其他一切处理部件高度整合在一起,大大提高数据传输速度.发布后好评如潮,我也没有忍住,入手了一台最低配的m ...
- Apple计划开发完全定制的GPU架构
根据Apple目前的GPU供应商,英国Imagination Technologies事务所透露,为了驱动未来新款设备的GPU,Apple将自行开发定制的图形架构.新GPU将在15个月到未来两年内完工 ...
- 简单开发Apple Watch的步骤
好久没写博客了,自己这两年自从孩子出世,也慢慢懈怠了.实在有点对不住了,换了个新公司,也有点时间可以写写东西了. 前几天苹果刚刚发布Apple Watch,Xcode6也更新了watchKit,正好 ...
- Xamarin开发Anroid应用介绍
第1章 Xamarin开发Anroid应用介绍 如今智能手机已经盛行了好几年,而针对这些智能手机的软件开发也变得异常火热.但是在Android平台下只能使用Java开发,iOS平台下也只能使用Obj ...
最新文章
- javascript定时器
- python汽车行驶工况_什么叫车辆行驶工况
- 一天一个类,一点也不累之HashSet
- redhat 添加ssh端口_Linux修改SSH远程登录端口 --服务器安全篇
- 那英、那狗、那年、那事
- vue调用企业微信API详细过程
- centos文件锁定解锁_解锁后轻松替换锁定的文件
- ActivityManagerService启动过程
- java中调用cmd命令被阻塞无法返回和继续执行
- 优启通制作系统u盘_EasyU优启通U盘启动盘制作工具BIOS+UEFI双启无捆绑
- STM32单片机配置FPGA
- HiveOnSpark
- 统一信息管理平台服务器,4A统一安全管控平台
- OneKeyGhost工具进行备份还原windows操作系统
- 开源智慧党建小程序源码系统+搭建教程
- Android系统下 SD卡各文件夹
- 华为笔记本键盘说明图_【华为 MateBook 13 笔记本电脑外观细节】LOGO|键盘|屏幕_摘要频道_什么值得买...
- 如何制作gif图片?
- 小灰灰的springboot的学习之路(三):配置mybatis和数据库
- 国信蓝点杯第二届(2011)C语言大赛样题整合
热门文章
- 云南工商学院计算机录取分数,云南工商学院录取分数线2021是多少分(附历年录取分数线)...
- leetcode解题总览
- Godot中的GIProbe和Baked lightmaps
- mysql用户的创建、修改、删除与密码修改
- MAML:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks论文精读及详解
- 30种常用管理工具模型整理分享(上)
- 总结一周:变量,数据类型,循环,函数
- 卡巴斯基KIS的激活方法
- aix 安装oracle smit install_latest,在AIX 5L上快速部署Oracle 9i
- 新框架(BSF_JAVA)环境部署个人总结