随着iPhone6s与6s plus的到来,苹果给我们展现了一种全新的交互方式:重按手势。你可能知道,这个特性已经在Apple Watch和MacBook上推出了,不过那时叫Force Touch,就是字面上的意思,给用户的交互添加一种新的维度。

如果你很好奇iPhone的Force Touch为啥要更名为3D Touch,那告诉你吧,you’re not alone(译者注:请用MJ的调子唱出来…)。不久前,之前也对这名字纠结不已的Craig Federighi(译者注:Apple高级副总裁)介绍了这个新特性,第一条微博就这样产生了。也不知道Force Touch这名字有啥不好的,就因为有太多星球大战的梗?(译者注:其实我不知道这梗…)

但是,Force Touch和3d Touch确实不一样!Force Touch只能识别重按。这方面3D Touch要灵敏多了,它能够识别按压的力度。

虽然说,这点不同看起来无足轻重,但是这使开发者能开发更多精确计量方面的App。比如这一款名为Gravity的应用,它利用Force Touch让你的iPhone成为了一个电子秤。虽然这款App被Apple拒了,但是这创意简直太棒了。所以,为了展示3D Touch的工作流程,我们来做一个简单的App。

先去下载这个初始案例。初始案例中只有一个空的Single View。我在里面创建了App必要的UI元素(UILabelUIImage),并关联了ViewController.swift

这个App的设计很简单:ViewController上有两个Label:一个标题和一个显示按压百分比的文本。

那…开始写代码吧!在iPhone6s和6s Plus上,UITouch对象多了两个CGFloat类型的属性,分别是forcemaximumPossibleForceforce表示按得有多重,1.0表示常规状态的值。maximumPossibleForce表示能承受的最大压力值。

无论什么情况,当用户触摸屏幕时,touchesBegan方法会被调用,接着就是touchesMoved(如果用户手指在屏幕上滑动,那么touchedCancelledtouchesEnded也会被调用)。在这个App中,我们只需要关注touchesMoved方法。touchesMoved有两个参数:toucheseventtouches是一个装着UITouch对象的NSSet类型集合(集合无序,并且无重复)。我们必须要确保在touches中只有一个UITouch对象,但也有考虑不完全的时候,所以强烈建议大家先利用可选绑定来判断touches.firsttouches中的第一个UITouch对象)是否是空。在ViewController.swift中添加以下代码:

override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first {
if #available(iOS 9.0, *) {
if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
// 3D Touch capable
}
}
}
}

在这个if判断中,还需要添加判断当前设备是否支持3D Touch的代码。如果你只是做来玩,那就没必要验证。但是,如果是要上架的App,那就必须要判断,毕竟像iPhone6这些旧设备不支持3D Touch。

除此之外,我还使用了#available语句(Swift 2.0)对当前系统是否是iOS9+做了判断。(如果你想学习更多Swift 2.0相关的知识,我就更加推荐你阅读这篇文章了。)同样,如果你的编译环境是iOS9.0+,那么这个判断可以省略。

要得到按压百分比?那太简单了,只需要用force属性除以maximumPossibleForce就可以了(例如:touch.maximumPossibleForce),maximumPossibleForce表示能承受的最大压力值。然后,更新文本:

override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first {
if #available(iOS 9.0, *) {
if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
// 3D Touch capable
let force = touch.force/touch.maximumPossibleForce
forceLabel.text = "\(force)% force"
}
}
}
}

如果你在iPhone6s/6s Plus上跑这个程序,按屏幕时就能看到压力百分比了。但是,其实我们更想知道放在iPhone上物体的重量,而不是百分比。根据Ryan McLeod的App可以知道,传感器的计量范围的最大值是385g。因此,maximumPossibleForce就相当于385g(相当于3.8N)。通过简单的计算,就可以把压力百分比转为克。需要做的仅仅是用百分比*385。对于重于385g的物体,就把label改成类似于“385+ grams”这样的文本好了。

到此,touchesMoved方法中的代码更新为:

override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first {
if #available(iOS 9.0, *) {
if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
if touch.force >= touch.maximumPossibleForce {
forceLabel.text = "385+ grams"
} else {
let force = touch.force/touch.maximumPossibleForce
let grams = force * 385
let roundGrams = Int(grams)
forceLabel.text = "\(roundGrams) grams"
}
}
}
}
}

然后…你就有一个电子秤App…

还有一个小问题:当物体或者触摸事件结束之后,文本没有重置。你可以实现touchesEnded方法来达到效果:

override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
forceLabel.text = "0 gram"
}

主屏幕上的快捷操作

另一个3D Touch的用法是主屏幕上的快捷操作。快捷操作可以让用户从快捷方式直接跳转到App的某个地方。按压App icon快捷方式就会出现。在介绍3D Touch的时候,Twitter、Instagram等App就展示了这个新特性。

让我们来给刚才的电子秤App添加一个快捷操作吧(把白色背景换成蓝色)。要添加快捷操作,先打开工程目录中的info.plist(在导航栏上点击工程名,在TARTGET中找到info选项卡)。在这个文件中,添加UIApplicationShortcutItems数组。数组中的元素是包含一个快捷操作配置的字典:

  • UIApplicationShortcutItemType (必填):快捷操作的唯一标识符(String类型)。建议将bundle ID或者其他唯一字符串作为标识符前缀。
  • UIApplicationShortcutItemTitle(必填):相当于快捷操作的title(String类型),用户可以看到。例如“显示最近一张照片”之类的文本。
  • UIApplicationShortcutItemSubtitle(可选):快捷操作的副标题(String类型)。例如“昨天拍摄的照片”。如果你想要给快捷操作添加一个icon,可以自定义,也可以使用系统自带的。
  • UIApplicationShortcutItemIconType(可选):表示你要选择哪种系统图标作为快捷操作的icon(String类型)。
  • UIApplicationShortcutItemIconFile(可选):表示给快捷操作添加自定义icon(String类型)。
  • UIApplicationShortcutItemUserInfo(可选):在快捷操作交互时传递的额外信息(译者注:类似于通知的UserInfo参数)(Dictionary 类型)。

在这个数组中,我们将会给自定义的快捷操作添加4个配置。然后,你的info.plist文件看起来应该是这样滴:

注意,我用到了$(PRODUCT_BUNDLE_IDENTIFIER)来代替com.appcoda.Scale(就是替代的 bundle ID)。这是出于安全考虑:无论在什么情况下,如果我在General中修改了 bundle ID,那整个工程的 bundle ID 就都变了,这势必会给项目带来不晓得影响。这样的话,我就需要手动去修改每个 bundle ID。在info.plist里面可以看到,其实每个 Bundle Identifier 配置项都是用的$(PRODUCT_BUNDLE_IDENTIFIER)来表示 bundle ID 在工程中的路径。

最后一件事,就是实现用户触发快捷操作的处理流程。快捷方式需要在AppDelegate.swiftperformActionForShortcutItem方法中处理。当使用快捷操作启动时,这个方法会被调用。所以,实现这个方法,并在方法中处理快捷操作:

func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {

    // Handle quick actions
completionHandler(handleQuickAction(shortcutItem)) }

这个方法需要调用completionHandler,并传入布尔值,这个布尔值取决于快捷操作成功与否。这里我们封装了一个handleQuickAction方法来处理快捷方式。如果有多个快捷操作,最好的方式是使用枚举,UIApplicationShortcutItemType作为枚举的rawValue(译者注:对枚举不熟悉可以参考这篇文章)。定义一个枚举,并实现handleQuickAction方法,在方法中修改背景色为蓝色。

enum Shortcut: String {
case openBlue = "OpenBlue"
} func handleQuickAction(shortcutItem: UIApplicationShortcutItem) -> Bool { var quickActionHandled = false
let type = shortcutItem.type.componentsSeparatedByString(".").last!
if let shortcutType = Shortcut.init(rawValue: type) {
switch shortcutType {
case .openBlue:
self.window?.backgroundColor = UIColor(red: 151.0/255.0, green: 187.0/255.0, blue: 255.0/255.0, alpha: 1.0)
quickActionHandled = true
}
} return quickActionHandled
}

一切都是这么简单。现在把程序跑起来,使用快捷操作来启动App,就可以看到背景已经是蓝色了。

还有一件事

还有一个问题你别忘了…在程序启动顺序方面,启动程序和使用快捷操作唤醒是有区别的。我们都知道,程序启动会调用willFinishLaunchingWithOptionsdidFinishLaunchingWithOptions方法。但是当使用快捷操作唤醒时,只会触发performActionForShortcutItem方法(译者注:这就意味着,使用快捷操作来启动会走三个方法,而使用快捷操作唤醒只会走一个,具体的方法列表如下图)。

如果你回头看didFinishLaunchingWithOptions方法,会发现里面我写了一行设置背景色为白色的代码。这个是在直接启动程序时用的。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.window?.backgroundColor = UIColor.whiteColor() return true
}

问题来了:当使用快捷操作唤醒程序时,willFinishdidFinishperformActionForShortcutItem都会被调用。所以背景色会先设置成白色,接着又被设置成了蓝色。显然你不想在使用快捷操作启动时,背景色被设置成白色。

要解决这个问题,我们需要在didFinishLaunchingWithOptions方法的实现中添加条件判断:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[NSObject: AnyObject]?) -> Bool {
print("didFinishLaunchingWithOptions called")
var isLaunchedFromQuickAction = false // Check if it's launched from Quick Action
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem { isLaunchedFromQuickAction = true
// Handle the sortcutItem
handleQuickAction(shortcutItem)
} else {
self.window?.backgroundColor = UIColor.whiteColor()
} // Return false if the app was launched from a shortcut, so performAction... will not be called.
return !isLaunchedFromQuickAction
}

通过判断可选值的UIApplicationLaunchOptionsShortcutItemKey得到用户是否是通过快捷操作启动。UIApplicationShortcutItem可以作为可选值的类型。如果程序是通过快捷操作启动的,我们可以直接调用handleQuickAction方法将背景色改为蓝色。

因为我们已经在didFinishLaunchingWithOption方法中调用了handleQuickAction,所以没必要再在performActionForShortcutItem方法中调用一次。所以最后我们返回了一个false,告诉系统不要再去调用performActionForShortcutItem方法。

再次运行程序!完美!

最后

3D Touch是给程序添加另一种交互方式的好方法。但是你还是不要忘了,目前还不是所有设备都支持3D Touch。

通过这篇文章,你应该能给你的App添加快捷操作,也能计量按压力度了。

顺便,你可以在这里下载程序的最终版。同样,欢迎大家留言。

【译】3D Touch之我见

Hey,现在有了支持3D Touch的iPhone和iOS9,这是一项伟大的科技杰作。让我们看看这为开发者和用户都带来了什么。文本主要是我对3D Touch的理解,然后列举了一些需要注意的点。

出师不利

本来我想写一篇关于3D Touch的导读文章,但是遇到一个问题——Xcode7的模拟器并不能模拟3D Touch。

苹果官方的说法是:

Xcode7.0中,你必须使用支持3D Touch的真机进行开发。因为Xcode7.0的模拟器不支持3D Touch。

这是个悲伤的故事,但是又有什么办法呢。我想,苹果应该会想办法模拟出来。可能在下一个Xcode发布版本中就能看到。

另一个问题则是新的iPhone还没有在波兰发售,可能还要等2周(译者注:作者写文在波兰iPhone发售以前)。

还有一个办法,我10月要在San Francisco和Palo Alto呆上整整一月,所以我可能会买一部iPhone,但不确定是6s还是6s plus。

如果买了设备,那肯定会发布一大波3D Touch的文章。

Peek and pop操作

这是苹果介绍3D Touch的第一个特性——或者说是两个特性。

  • 轻压(peek,轻度按压)操作能让用户在不离开当前界面的情况下预览内容。如果轻按某个选项能够弹出一个小的矩形视图,则表明它支持轻压操作。
  • peek手势弹出的视图应该足够大,这样内容就不会被手指挡住,从而用户可以选择是否重压,即pop操作(译者注:peek操作即轻按,用于预览,pop操作则是重压,用于进一步确认。pop能满足在预览之后,进入特定页面的需求)。
  • pop则是当用户在peek弹出的视图上加重按压力度,显示更详细的内容。
  • 即使peek能给用户足够多的信息,你也应该让用户将该操作转化为pop。pop所显示的界面应该和用户点击进入界面相同。
  • 请勿在peek预览的界面中放入按钮,因为用户手指一离开预览界面,预览界面就会消失,所以根本点不到按钮。
  • 当用户在预览界面中向上滑动时,peek可以提供一些快捷操作(quick action)。你可以在预览界面中添加一些快捷操作,这样用户就可以上滑,然后选择一个你所提供的操作了。
  • 如果你为某个选项提供了长按手势事件(touch-and-hold,或者叫long press),那么你可以用peek来代替长按手势,这是一个很好的尝试。
  • 如果你想使用快捷操作、peek和pop,那么记住在使用前先判断3D Touch是否可用。
  • 不是每个设备都支持peek和pop操作的,并且3D Touch也可能处于禁用状态。所以不要让某些事件只能由peek来触发。最好有一个备选方案,即视图也能通过长按手势来展示。

快捷操作

接下来,介绍一些用户在重压应用图标时的一些快捷操作。

  • 弹出框包含了主标题、副标题与图标。
  • 该操作可以在应用程序更新时,显示更新信息。
  • 你的应用在Home界面中,应该至少提供一个快捷选项。这样用户就可以使用手势操作你的应用,方便快捷。
  • 医用最多可以提供四个快捷操作。
  • 不要使用快捷操作来提醒用户更新、变更之类的事。如有需要,通知(Notifications)更能胜任这些任务。
  • 快捷操作的命名应该简洁,如有需要,还应该有副标题和图标。尽量让用户明确该操作的作用。如果提供了副标题,那么标题栏将会更长,如果大小不能适应,系统会自动截取。如果没有副标题,那么主标题过长会自动换行。

最后

3D Touch是一个非常爽的特性,它提供了全新的交互方式。设备中包含了一个线性振动器(Taptic Engine),所以按压屏幕时,设备能有一定响应——太好了,迫不及待想要试试。

非常遗憾,苹果没有在最新的Xcode 7 beta 2中解决无法模拟的问题,还是希望他们尽快搞定吧——或许他们不修复是为了增加销量,因为用户已经迫不及待的想要试试这个新特性了,而最简单粗暴的方式,就是买个新设备 :D。

我已经迫不及待的想要尝试基于3D Touch的应用了,如游戏和画图,还有一些我想象不到的应用。或许还可以看到计量重量的应用,比如称一个水果的重量,或是一个放置在屏幕上的物体的重量等等 :>。

3D Touch介绍:电子秤App与快捷操作的更多相关文章

  1. 微信成为首批支持iPhone 6s /Plus 上 3D Touch 功能的 App

    2015苹果新品发布会上微信成为首批支持iPhone 6s 和 iPhone 6s Plus 上 3D Touch 功能的 App.通过 3D Touch,微信用户将可以通过更精减的操作完成基本任务, ...

  2. iOS开发--3D Touch的基本使用

    1.桌面快捷菜单项 效果如图: 桌面快捷菜单 点击之后的效果如图: 点击桌面快捷菜单的效果 接下来看下具体实现:1).在-application:didFinishLaunchingWithOptio ...

  3. iOS9 - 采用3D Touch

    iPhone 6s/6s Plus提供了触摸屏的另一个维度的操作手势-3D Touch,通常有下面两种应用场景: 在主屏幕上重按APP图标可以提供进入APP特定功能的快捷菜单 在APP内部,可以通过重 ...

  4. iOS 3D Touch实践

    本文主要讲解3DTouch各种场景下的开发方法,开发主屏幕应用icon上的快捷选项标签(Home Screen Quick Actions),静态设置 UIApplicationShortcutIte ...

  5. iOS 3D Touch 适配开发

    3D Touch的主要应用 文档给出的应用介绍主要有两块: 1.A user can now press your Home screen icon to immediately access fun ...

  6. Swift 玩转 3D Touch 之 Peek & Pop

    什么是3D Touch 3D Touch 是iOS9之后专为 iPhone6s 机型加入的新特性,这一新技术移植于 Mac Book 上的 ForceTouch 更准确地说应该是 ForceTouch ...

  7. 3d touch 应用 2 -备用

    一.引言 在iphone6s问世之后,很多果粉都争先要体验3D Touch给用户带来的额外维度上的交互,这个设计之所以叫做3D Touch,其原理上是增加了一个压力的感触,通过区分轻按和重按来进行不同 ...

  8. 3D touch 的 应用 --备用

    在iPhone 6s和iPhone 6s Plus中Apple引入了3D Touch技术.3D Touch的触控技术,被苹果称为新一代多点触控技术.其实,就是此前在Apple Watch上采用的For ...

  9. iOS 3D Touch功能 3 -备

    新的触摸体验——iOS9的3D Touch 一.引言 二.在模拟器上学习和测试3D Touch 附.SBShortcutMenuSimulator的安装和使用 三.3D Touch的主要应用 四.3D ...

随机推荐

  1. Zip 压缩、解压技术在 HTML5 浏览器中的应用

    JSZip 是一款可以创建.读取.修改 .zip 文件的 javaScript 工具.在 web 应用中,免不了需要从 web 服务器中获取资源,如果可以将所有的资源都合并到一个 .zip 文件中,这 ...

  2. WCF服务创建与使用(双工模式)

    昨天发布了<WCF服务创建与使用(请求应答模式)>,今天继续学习与强化在双工模式下WCF服务创建与使用,步骤与代码如下. 第一步,定义服务契约(Service Contract),注意Se ...

  3. Architecture Pattern: Publish-subscribe Pattern

    1. Brief 一直对Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通过这两篇Blog来梳理这两种模式.若有纰漏请大家指正. 2. Role Publisher: ...

  4. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  5. chm转换为html的超简单方法

    在Windows下chm转换为html的超简单方法(反编译CHM文件的方法) 通过调用Windows命令,将chm 文件转换为html 文件. 方法: 命令行(cmd),输入hh -decompile ...

  6. C语言学习010:fopen读写文件

    在文件input.csv文件中,我们有数据如下 Apple Pear Litchis Pineapple Watermelon 现在我们将input.csv文件下的读取并写入到output.csv文件 ...

  7. 创建html元素

    如果我要创建一个div元素. 1.使用DOM对象创建: 使用document.createElement('div')方法创建元素. 2.使用JQuery创建: 使用$('<div>通过J ...

  8. Ajax代码简单封装。

    function ajax(url, onsuccess, onfail) {    var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest( ...

  9. Internet 信息服务承载说明

    若要运行由 Internet 信息服务 (IIS) 承载的示例,必须确保 IIS 已正确安装且正在运行. 在 Windows Server 2008 R2 上安装 IIS 7.5 版 在"服 ...

  10. Css Ajax Entlib aspnetpager

    ---样式引导----- http://bootswatch.com/ -------ajaxToolKit----------- www.asp.net/ajax--------微软企业库----- ...