Passer des données d'un ViewController vers un UIView

Dans ta première version, quand je mettais 2 doigts sur l’écran il me comptais 2,
Avec la nouvelle version il ne compte plus qu’un et je n’ai pas les 2 imageView

Cela ne vas pas être simple à tester, je n’ai pas de câble sous la main pour connecter mon MBP 16 pouces à un Device. 4 ports USB-C c’est bien, mais des fois un petit port USB-A c’est utile …

Ça c’est sur :sweat_smile:
Je refais des tests demain

Salut @Draken,

J’ai trouvé :

view.isMultipleTouchEnabled = true

C’était simplement au niveau de la vue, par contre je n’ai pas 1 imageView par doigt, je regarde ça de mon coté

override func viewDidLoad() { 
  super.viewDidLoad()
  self.view.isUserInteractionEnabled = true
  actualiserInterface() 
}

Je vois. Au lieu d’activer le multi-touch sur la vue, j’ai tout simplement activé le touch de base (déjà activé par défaut !). A croire que j’ai tapé le code à une heure du matin, en vitesse !

Ce genre de bugs est fréquent à cause d’un phénomène psychologique courant chez les développeurs : en relisant un code, on ne voit pas ce qui est réellement présent sur l’écran, mais ce qu’on voulait écrire.

C’est pourquoi un second regard est souvent fort utile pour trouver les « bugs évidentes ».

Merci à toi,
Très connu ce phenomène :joy:

J’ai cherché aujourd’hui mais compliqué de trouver comment ajouter 1 imageView par touch :thinking:
(La boucle « for » n’as pas fonctionné)

Salut!

Je ne sais pas si tu as déjà jeté un coup d’oeil dessus mais la doc d’Apple est assez complète. (Raccourci: Maj+Cmd+0)

https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_touches_in_your_view/implementing_a_multi-touch_app

C’est un exemple qui explique plus ou moins ce que tu veux faire!

Bonne lecture,

Nicolas.

Edit : Bon, d’après le nom de tes fonctions, tu as du y jeter un coup d’oeil ahah

Salut @Nicow

C’est ce que j’avais fait au départ, mais @Draken m’as fait changer d’avis, et effectivement, sa solution avec les imageView fonctionnement mieux.
Juste ce Problème ou j’en ai qu’en pour plusieurs touch :thinking:

J’ai l’impression qu’il ne relance pas le createViewForTouch qui est dans la boucle for

Salut,

Rajoutes des « prints » si tu as un doute sur le lancement d’une fonction ou non.

Comme le dis Nicow, tu peux insérer des instructions print() dans le code, pour suivre l’évolution du flux programmatique.

Exemple :

J’ai ajouté un print au début de createViewForTouch(), affichant le contenu de la variable touch. Cela permet de savoir combien de fois la fonction est appelé en réponse à un événement clavier.

Si tu trouves que l’information est trop dense, pas besoin d’afficher le contenu de Touch. Un simple texte suffit.

func createViewForTouch( touch : UITouch ) {
    print ("- Appel createViewForTouch)

Salut @Draken,

J’avais essayé entre temps, la fonction est bien appelée mais l'imageView part du premier touch pour aller au second et ainsi de suite.
Il n’y a qu’un seul imageView peut importe le nombre de touch…

Je viens de tester sur mon iPad Pro. Chez moi, ça fonctionne …

On vas reprendre au début. Créé un nouveau projet avec ce code ultra-minimaliste :

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        super.view.isMultipleTouchEnabled = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print ("Nb Touch : ", touches.count)
    }
    
} 

Pour vérifier le multi-touch.

Lorsque iOS détecte un nouvel événement tactile, il appelle la fonction touchesBegan en lui passant la liste des points de contacts, stockée dans la variable touches.

La propriété .count indique le nombre d’éléments dans la liste.

Ça fonctionne chez moi aussi, c’est le createViewForTouch qui ne me génère pas d'imageView pour tout les touch,

Et avec ça ?

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        super.view.isMultipleTouchEnabled = true
        super.view.backgroundColor = UIColor.green
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print ("Nb Touch : ", touches.count)
        for touch in touches {
            createViewForTouch(touch: touch)
        }
    }
    
    func createViewForTouch( touch : UITouch ) {
        let imageView = UIImageView()
        imageView.image = UIImage(systemName: "bolt.circle.fill")
        imageView.frame.size = CGSize(width: 100, height: 100)
        imageView.center = touch.location(in: self.view)
        self.view.addSubview(imageView)
    }
    
}

A chaque Touch, cela crée un UIView sur l’image, sans mémorisation, ni destruction ultérieur.

J’ai ajouté une ligne supplémentaire dans l’initialisation (viewDidLoad) pour mettre le fond d’écran en vert, afin d’améliorer la présentation de l’affichage.

Je l’ai testé en posant 4 doigts sur l’écran, en une seule opération. Ça fonctionne …

Screen Shot 2020-04-14 at 17.27.52

Enfin presque … Comme je l’ai dis dans un autre post, il suffit d’un infime décalage être le moment où les doigts touchent l’écran, pour que iOS interprète cela comme plusieurs contacts différents.

Grace au print() inséré dans le code, on peut voir que « mon touch à 4 doigts » a été interprété par iOS comme un Touch à 2 doigts, suivi de deux autres à 1 doigt !!

En faisant d’autres tests, j’ai eu un 3 + 1, un 1 + 2 + 1, etc … C’est normal et ne gêne pas le fonctionnement attendu de l’application.

Si l’application a vraiment besoin d’attendre 4 touch simultanés pour faire quelque chose, on peut utiliser des outils capable de tenir compte automatiquement des « petites imperfections humaines » : les détecteurs de gestures. C’est un « sujet avancé » que tu verras plus tard.

Ça fonctionne !

À priori, il manquait juste la ligne :

let imageView = UIImageView()

J’ai bien un imageView par touch désormais, mais en rajoutant la fonction removeViewForTouch les imageView ne disparaissent plus :thinking:

Pourtant tout m’as l’air cohérent.

Merci encore pour ton aide :pray:

Je te met mon code ci-dessous :

func createViewForTouch( touch : UITouch ) {
    print ("Appel CreateView")
    let imageView = UIImageView()
    imageView.image = UIImage(named: "raphisme")
    imageView.frame.size = CGSize(width: 100, height: 100)
    imageView.isMultipleTouchEnabled = true
    imageView.center = touch.location(in: self.view)
    self.view.addSubview(imageView)
    touchViews[touch] = imageView
    
}

    
func removeViewForTouch (touch : UITouch ) {
        if let view = touchViews[touch] {
        view.removeFromSuperview()
        touchViews.removeValue(forKey: touch)
    }
}

La ligne

imageView.isMultipleTouchEnabled = true

ne sert absolument à rien ! Pas besoin de rendre les imageries sensible aux événements tactiles, puisqu’ils ne font rien à part être affichés sur l’écran.

1 « J'aime »

J’ai repris le code pour remettre le tableau, et la gestion de l’effacement des images.

Testé sur mon iPad Pro. Cela fonctionne parfaitement …

import UIKit

class ViewController: UIViewController {

var touchViews = [UITouch:UIImageView]()

override func viewDidLoad() {
    super.viewDidLoad()
    super.view.isMultipleTouchEnabled = true
    super.view.backgroundColor = UIColor.green
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    print ("Nb Touch : ", touches.count)
    for touch in touches {
        createViewForTouch(touch: touch)
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        removeViewForTouch(touch: touch)
    }
}

func createViewForTouch( touch : UITouch ) {
    let imageView = UIImageView()
    imageView.image = UIImage(systemName: "bolt.circle.fill")
    imageView.frame.size = CGSize(width: 100, height: 100)
    imageView.center = touch.location(in: self.view)
    self.view.addSubview(imageView)
    touchViews[touch] = imageView
}

func removeViewForTouch (touch : UITouch ) {
    if let view = touchViews[touch] {
        view.removeFromSuperview()
        touchViews.removeValue(forKey: touch)
    }
}

}

Quelques améliorations pour rendre les images dynamiques, si les doigts bougent, comme dans l’exemple d’Apple.

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            moveView(touch: touch)
        }        
    }

    func moveView(touch : UITouch) {
        if let view = touchViews[touch] {
            view.center = touch.location(in: self.view)
        }
    }

Rien de compliqué. Quand iOS détecte qu’un événement tactile se déplace sur l’écran, il appelle la fonction touchesMoved(). La fonction moveView() récupère la nouvelle position et déplace l’imageView.

J’ai aussi ajouté une fonction pour gérer l’événement touchesCancelled, qui se produit si un événement tactile se termine de manière anormale. Quand le doigt sort de l’écran, par exemple.

C’est une vieille fonction datant des premières versions d’iOS. Il me semble que maintenant ce n’est plus utile, qu’iOS génère un événement touchesEnd() en cas de problème. Le code étant court, j’ai préféré l’ajouter par prudence.

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        removeViewForTouch(touch: touch)
    }
}