3DTouch - Échelles sur iPhone: achèvement

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.

image

Comme je l'ai dit, la fonctionnalité principale est prête, il n'y a que des améliorations:

  1. 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
  2. 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é.
  3. 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) // 1 view.addSubview(cicrcleView) // 2 } } 

Nous sélectionnons également le premier parmi l'ensemble des touches et travaillons avec cette touche

  1. Réglez le centre du cercle View sur le point de contact
  2. 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 " //  cicrcleView.removeFromSuperview() //   cicrcleView.transform = .identity //     } 

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

Source: https://habr.com/ru/post/fr417339/


All Articles