Dans le
dernier article, nous avons envisagé de travailler avec 3DTouch sur l'iPhone. Il ne reste plus qu'à terminer quelques coups et terminer notre application.

Comme je l'ai dit, la fonctionnalité principale est prête, il n'y a que des améliorations:
- Lorsque j'atteins la valeur maximale, je veux que la réponse aux vibrations fonctionne comme dans l'article de rétroaction Haptic sur iPhone 6s
- La mise à jour des valeurs dans UILabel se produit très rapidement (je pense que vous l'avez remarqué lors des tests), vous devez donc ajouter un peu de fluidité.
- Un cercle semi-transparent devrait apparaître au moment d'appuyer. Son diamètre devrait augmenter avec l'augmentation de la pression et diminuer avec la diminution de la pression
Les deux premiers points que je ne peux afficher ni à l'aide de captures d'écran ni à l'aide de
gifs animés . Par conséquent, effectuez les ajouts décrits ci-dessous et vérifiez-le vous-même sur vos appareils. Et ici, je vais démontrer le troisième point. Mais les modules complémentaires font tout cela ensemble.
Retour de vibration Retour haptique
Nous importons le framework
AudioToolbox avant la déclaration de la classe
ViewController et ajoutons également la propriété
isPlaySound pour exclure la
réponse répétée de la
réponse de vibration.
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 ...
Ensuite, apportez des modifications à la
méthode touchesMoved (: :) pour qu'elle ressemble à ceci:
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) " } } } } }
Rien de compliqué - lorsque vous exécutez l'application iOS, et dans ce cas, lors de l'initialisation du
ViewController et de la création d'une propriété de la classe
isPlaySound, nous permettons de lire des sons, y compris les réponses vibratoires. Lorsque la pression maximale est
atteinte, isPlaySound (1) est vérifié et s'il est
vrai , la vibration est effectuée et l'interdiction (2) de jouer la vibration est immédiatement déclenchée. Cette interdiction est levée (3) si la force de pression devient inférieure à la valeur maximale possible.
Mise à jour fluide
Maintenant sur la douceur. Les mises à jour des étiquettes arrivent très rapidement, avec la vitesse de réponse de la
méthode touchesMoved (: :) , ce qui représente plusieurs centaines d'opérations par seconde. Pour réduire le taux de rafraîchissement de l'étiquette, j'ai ajouté une propriété de la classe
ViewController isUpdate et défini les
observateurs de propriété
didSet .
var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } }
L'essence d'une telle construction est que dès que nous définissons cette propriété sur false, elle revient à true après
0,01 seconde. Par conséquent, lors de l'écriture de texte dans
UILabel, nous
définirons la valeur de la propriété
isUpdate sur
false et n'autoriserons pas la mise à jour des étiquettes jusqu'à ce qu'elle devienne
vraie . Par conséquent, les enregistrements ne seront mis à jour avec nous qu'une fois tous les centièmes de seconde.
Dans la
méthode touchesMoved (: :) , dans la branche où nous affichons le% force et poids en grammes, changez le code comme suit:
if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false }
Ce sera suffisant pour donner une fluidité lors de la mise à jour des étiquettes
Visualisation tactile
Tout d'abord, créons un
UIView et
rendons -le translucide et rond. Pour ce faire, ajoutez une propriété de la classe
ViewController et
définissez les paramètres initiaux dans la méthode
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 }
Il y a une propriété, elle a une
vue , mais à quel moment faut-il l'ajouter à l'écran? Il est logique qu'au moment où vous commencez à toucher. Dans le
ViewController, vous devez ajouter la
méthode touchesBegan (: :) override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view)
Nous sélectionnons également le premier parmi l'ensemble des touches et travaillons avec cette touche
- Réglez le centre du cercle View sur le point de contact
- Ajouter cicrcleView à l'écran
Dans la
méthode touchesMoved (: :) dans la branche où les pourcentages et le poids en grammes sont traités, ajoutez la ligne:
cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20))
Ici, nous définissons la matrice de transformation pour augmenter la taille du
cicrcleView en hauteur et en largeur. Les valeurs que j'ai transférées dans cette matrice sont le résultat de la sélection des valeurs les plus pratiques. Méthode de sélection "poke". Vous pouvez donc expérimenter et choisir les valeurs qui vous conviennent.
Et enfin, à la fin du toucher, vous devez annuler la transformation de
cicrleView et la supprimer de l'écran. Nous avons déjà une méthode où vous pouvez travailler. Dans la
méthode touchesEnded (: :) , ajoutez deux lignes:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 "
Le code complet de
ViewController ressemble à ceci:
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 } }
Code de fichier
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() } }
Projet Link sur
GitHub