- 原文链接: 3D Force Touch: beyond peek & pop
- 译文出自 : 掘金翻译计划
- 译者 : shiguol(SAlex)
- 校对者 : cdpath (cdpath) nathanwhy (nathan)
几天前我买了部 iPhone 6S,接着我被 3D touch 功能深深地吸引住了,于是迫不及待地体验了一番。
在一个应用程序中,Peek 和 pop 是一个很出彩的特性。不过话说回来:我们没有太多的控制权。我们只能添加一个预览功能和几个动作 - iOS 系统会管理剩下的工作。
因为我探索了 3D Touch 功能,就一直在思考与内容互动的新方式。Peek 和 pop 是一个很好的交互方式; 但我真正想要的是创建自定义的控制技术。
我们需要考虑的是,由于 3D touch 仅在 iPhone 6S 和 6S Plus 上提供,所以不应该存在仅能使用该动作执行的功能。用户应不依赖 3D touch 也可以完成所有功能(就像使用 Peek 和 pop 实现的一样), 而 3D touch 最好只提供额外的交互体验。
访问 force 属性
新的 force 属性在 UITouch 类中。如果想获得用户 touch 事件,我们应该重写 touches 相关方法(类如:touchesBegan, touchesMoved, touchesEnded), 或者继承相关类(例如 UIView,UIButton;见例1),抑或继承实现一个手势(见下文,例 2 和 例 3);
import UIKit.UIGestureRecognizerSubclass
class ForceGestureRecognizer: UIGestureRecognizer {
var forceValue: CGFloat = 0
override func touchesBegan(touches: Set, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
state = .Began
handleForceWithTouches(touches)
}
override func touchesMoved(touches: Set, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
state = .Changed
handleForceWithTouches(touches)
}
override func touchesEnded(touches: Set, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
state = .Ended
handleForceWithTouches(touches)
}
func handleForceWithTouches(touches: Set) {
if touches.count != 1 {
state = .Failed
return
}
guard let touch = touches.first else {
state = .Failed
return
}
forceValue = touch.force
}
}
在这里,我们可以看到 force 属性值介于 0.0 ~ 6.667 之间;关于该值的更多讨论,推荐看这篇文章探索 Apple`s 3D Touch.
例 1: Force Button
Force Button 是 UIButton 的子类,可根据按压的力量变化来修改按钮的阴影属性(见文章开头处视频)。
func shadowWithAmount(amount: CGFloat) {
self.layer.shadowColor = shadowColor.CGColor
self.layer.shadowOpacity = shadowOpacity
let widthFactor = maxShadowOffset.width/maxForceValue
let heightFactor = maxShadowOffset.height/maxForceValue
self.layer.shadowOffset = CGSize(width: maxShadowOffset.width - amount * widthFactor, height: maxShadowOffset.height - amount * heightFactor)
self.layer.shadowRadius = maxShadowRadius - amount
}
上面的函数依据按压力的大小来修改按钮的阴影。你可以找到另外一个例子,解释了如何依据按压力的大小来缩放按钮,[文章在这里](github.com/Produkt/3dF…)。
这个按钮使用 3D touch 技术只实现了视觉上的反馈,它没有任何额外的功能。其实,它可以在用户用力按压按钮时系统回调的事件(如 _UIControlEvents.ForceMaxInside)中进行我们自己额外的事件响应。
Example 2: Zooming
我们都是用来双指的捏来实现放大和缩小,这样操作起来感觉自然。然而,有时候当你单手拿着手机时,双指缩放手势操作起来会感觉怪怪的。谷歌地图应用程序尝试通过使用 doble-tap-longPress-drag 手势来解决这个的问题(这感觉怪怪的,如果你不使用它)。
当使用 ForceGestureRecognizer 手势时(见上面的代码),该手势在你拖拽时也很容易放大和缩小。如果你有一个 iPhone6S 可以试一试,这感觉太棒了。
为了达到这个效果,我简单地应用一个 CATransform3D 缩放效果到 ImageView 的层。这样,图像从它的中心进行缩放。通过按住并移动我的手指(缩小到一个特定的区域),我就可以根据手指的位置更新图片的锚点。
func imagePressed(sender: ForceGestureRecognizer) {
let point = sender.locationInView(self.view)
let imageCoordPoint = CGPointMake(point.x - initialFrame.origin.x, point.y - initialFrame.origin.y)
var xValue = max(0, imageCoordPoint.x / initialFrame.size.width)
var yValue = max(0, imageCoordPoint.y / initialFrame.size.height)
xValue = min(xValue, 1)
yValue = min(yValue, 1)
let anchor = CGPointMake(xValue, yValue)
mainImageView.layer.anchorPoint = anchor
let forceValue = max(1, sender.forceValue)
mainImageView.layer.transform = CATransform3DMakeScale(forceValue, forceValue, 1)
if sender.state == .Ended {
mainImageView.layer.anchorPoint = CGPointMake(0.5, 0.5)
mainImageView.layer.transform = CATransform3DIdentity
}
}
最后一个关于 3D_touch 的交互特性我觉得就是控制动画了.不过,实话说,我还没有发现这种相互作用的任何有趣的用途(不是作为精细调谐),但我想提一提它(有人可能会发现它很有用)。
这里有一个动画视频是由 3D_touch 进行的控制。
这里还有给设计师和工程师的一些示例演示了使用 3D_touch 进行交互的方法。我希望我已经说服你去尝试 3D_touch。
我想通过推荐[FlexMonkey 的博客](flexmonkey.blogspot.com.es)最新文章:[3D Retouch](flexmonkey.blogspot.com.es/2015/10/3D-…),在这篇文章中,他使用 3D Touch 修改滤镜的强度。
整个项目在这里[github](github.com/Produkt/3dF…)。
特别感谢 @pivalue