No
último artigo, vimos como trabalhar com o 3DTouch no iPhone. Agora, resta concluir algumas pinceladas e finalizar nosso aplicativo.

Como eu disse, a principal funcionalidade está pronta, existem apenas melhorias:
- Ao atingir o valor máximo, desejo que a resposta à vibração funcione como no artigo de feedback da Haptic no iPhone 6s
- A atualização dos valores no UILabel acontece muito rapidamente (acho que você notou isso ao testar), portanto, é necessário adicionar alguma suavidade.
- Um círculo semitransparente deve aparecer no momento do pressionamento. Seu diâmetro deve aumentar com o aumento da pressão e diminuir com a diminuição da pressão
Os dois primeiros pontos que não posso exibir usando capturas de tela ou
gifs animados. Portanto, faça as adições descritas abaixo e verifique você mesmo em seus dispositivos. E aqui vou demonstrar o terceiro ponto. Mas vamos adicionar complementos juntos.
Feedback de vibração Feedback de háptica
Importamos a estrutura
AudioToolbox antes da declaração da classe
ViewController e também adicionamos a propriedade
isPlaySound para excluir a
resposta repetida da
resposta de vibração.
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 ...
Em seguida, faça alterações no
método touchesMoved (: :) para que fique assim:
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) " } } } } }
Nada complicado - quando você executa o aplicativo iOS e, nesse caso, ao inicializar o
ViewController e criar uma propriedade da classe
isPlaySound, habilitamos a capacidade de reproduzir sons - incluindo respostas de vibração. Quando a pressão máxima é
atingida, isPlaySound (1) é verificado e, se for
verdade , a vibração é executada e a proibição (2) de reproduzir a vibração é imediatamente acionada. Esta proibição é levantada (3) se a força de prensagem se tornar menor que o valor máximo possível.
Atualização suave
Agora sobre suavidade. As atualizações de rótulos acontecem muito rapidamente, com a velocidade de resposta do método
touchesMoved (: :) , e são centenas de operações por segundo. Para reduzir a taxa de atualização do rótulo, adicionei uma propriedade da classe
ViewController isUpdate e defina os
observadores da propriedade
didSet .
var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } }
A essência dessa construção é que, assim que configuramos esta propriedade como false, ela retorna para true após
0,01 segundos. Assim, ao escrever texto em
UILabel, definiremos o valor da propriedade
isUpdate como
false e não permitiremos atualizar os rótulos até que se torne
verdadeiro . Portanto, os registros serão atualizados conosco no máximo uma vez a cada centésimo de segundo.
No método
touchesMoved (: :) , no ramo em que exibimos a% força e peso em gramas, altere o código da seguinte maneira:
if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false }
Isso será suficiente para dar suavidade ao atualizar rótulos
Visualização por toque
Primeiro, vamos criar um
UIView e torná-lo translúcido e redondo. Para fazer isso, adicione uma propriedade da classe
ViewController e faça as configurações iniciais no método
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 }
Existe uma propriedade, ela tem uma
View , mas em que ponto ela deve ser adicionada à tela? É lógico que, no momento em que você começa a tocar. No
ViewController, você precisa adicionar o método
touchesBegan (: :) override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view)
Também selecionamos o primeiro do conjunto de toques e trabalhamos com esse toque
- Defina o centro do círculoVer como o ponto de toque
- Adicione cicrcleView à tela
No método
touchesMoved (: :) na ramificação onde são processadas porcentagens e peso em gramas, adicione a linha:
cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20))
Aqui, definimos a matriz de transformação para aumentar o tamanho do
cicrcleView em altura e largura. Os valores que transferi para essa matriz são o resultado da seleção dos valores mais convenientes. Método de seleção "puxão". Assim, você pode experimentar e escolher os valores que são convenientes para você.
E, finalmente, no final do toque, você precisa cancelar a transformação do
cicrleView e removê-lo da tela. Já temos um método no qual você pode trabalhar com isso. No método
touchesEnded (: :) , adicione duas linhas:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 "
O código completo do
ViewController é assim:
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 } }
Código do arquivo
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() } }
Vincular projeto no
GitHub