在
上一篇文章中,我们研究了如何在iPhone上使用3DTouch。 现在,需要完成几个步骤并完成我们的应用程序。

正如我所说,主要功能已经准备就绪,只有改进之处:
- 当达到最大值时,我希望振动响应像iPhone 6s上的触觉反馈文章一样起作用
- UILabel中的值更新非常迅速(我认为您在测试时注意到了这一点),因此需要增加一些平滑度。
- 半透明的圆圈应该出现在按压点处。 其直径应随压力增加而增大,而随压力减小而减小
前两点我无法使用屏幕截图或动画
gif来显示 。 因此,进行如下所述的添加操作,然后在设备上自行检查。 在这里,我将说明第三点。 但是,让我们的附加组件一起完成这一切。
振动反馈触觉反馈
我们在
ViewController类的声明之前导入
AudioToolbox框架,并添加
isPlaySound属性以排除振动响应的重复响应。
import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true ...
接下来,对
touchesMoved(::)方法进行更改,使其看起来像这样:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = "100%+ force" grammLabel.text = "385 " if isPlaySound { // // 1 AudioServicesPlaySystemSound(1519) isPlaySound = false // 2 } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true // // 3 forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " } } } } }
没什么复杂的-当您运行iOS应用程序时,在这种情况下,当初始化
ViewController并创建
isPlaySound类的属性时
,我们启用了播放声音的功能-包括振动响应。 当
达到最大压力
时,检查
isPlaySound (1),如果为
true ,则执行振动,并立即触发播放振动的禁止(2)。 如果按压力小于最大可能值,则取消此禁止(3)。
顺利更新
现在介绍平滑度。 标签更新以
touchesMoved(::)方法的响应速度非常快地完成,这是每秒几百次操作。 为了降低标签的刷新率,我添加了
ViewController isUpdate类的属性,并设置了
didSet属性
observers 。
var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } }
这种构造的本质是,只要将此属性设置为false,它就会在
0.01秒后返回true。 因此,在将文本写入
UILabel时,我们将
isUpdate属性的值设置为
false ,直到变为
true时才允许更新标签。 因此,记录与我们的更新不会超过百分之一秒。
在
touchesMoved(::)方法中,在显示以克为单位的强度和重量百分比的分支中,更改代码,如下所示:
if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false }
这足以在更新标签时提供平滑度
触摸可视化
首先,让我们创建一个
UIView并使它半透明和圆形。 为此,添加
ViewController类的属性并在
viewDidLoad()方法中进行初始设置
let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) // View 80 80 override func viewDidLoad() { super.viewDidLoad() forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.layer.cornerRadius = 40 // View - cicrcleView.alpha = 0.6 // 60% cicrcleView.backgroundColor = UIColor.red }
有一个属性,它具有
View ,但是应该在什么时候将其添加到屏幕上? 在您开始接触时,这是合乎逻辑的。 在
ViewController中,您需要添加
touchesBegan(::)方法
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view)
我们还从一组触摸中选择第一个,并使用该触摸
- 将circleView的中心设置为接触点
- 将cicrcleView添加到屏幕
在处理百分比和重量(克)的分支的
touchesMoved(::)方法中,添加以下行:
cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20))
在这里,我们设置转换矩阵以增加
cicrcleView的高度和宽度。 我转移到此矩阵的值是选择最方便的值的结果。 选择方法“戳”。 因此,您可以进行实验并选择方便的值。
最后,在触摸结束时,您需要取消
cicrleView的转换并将其从屏幕上删除。 我们已经有了一种可以解决的方法。 在
touchesEnded(::)方法中,添加两行:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 "
完整的
ViewController代码如下所示:
import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } } let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) override func viewDidLoad() { super.viewDidLoad() forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.layer.cornerRadius = 40 cicrcleView.alpha = 0.6 cicrcleView.backgroundColor = UIColor.red } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) // 1 view.addSubview(cicrcleView) // 2 } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = "100%+ force" grammLabel.text = "385 " if isPlaySound { AudioServicesPlaySystemSound(1519) isPlaySound = false } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false } cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20)) } } } } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.removeFromSuperview() cicrcleView.transform = .identity } }
ScaleView文件
代码 :
import UIKit @IBDesignable class ScaleView: UIView { override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() context?.setStrokeColor(UIColor.red.cgColor) context?.setLineWidth(14.0) context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 2 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) context?.strokePath() context?.setLineWidth(1.0) context?.setStrokeColor(UIColor.lightGray.cgColor) context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 4 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) context?.strokePath() } }
GitHub上的链接项目