Fulltitude de UIPanGestureRecognizer

Bonjour,


 


si on a plein de UIPanGestureRecognizer , essaie-t-on de n'en faire qu'un avec un switch/case of sur le UIPanGestureRecognizer reçu, n question, ou y-a-t-il une technique plus intelligente et plus compliquée, genre un petite classe qui va bien ?


 


J'ai fait plein d'essais, et je m'embrouille tout seul.


 


Merci d'avance


Réponses

  • AliGatorAliGator Membre, Modérateur
    Pourquoi aurais-tu plusieurs UIPanGestureRecognizer sur la même vue ? Je ne comprends pas trop ta question...
  • Par ex sur cette vidéo, j'en ai 4, mais je vais en avoir des dizaines (points de courbes et de tangentes)


     


    Je me disais aussi qu'avec un switch, ce serait pareil. Autant de case of que de panGestureRecognizer.


     


    Je travaille sur un tableau des points, actuellement



    tablo[i].addGestureRecognizer(UIPanGestureRecognizer)

    par contre, comment transmettre un paramètre supplémentaire (le point - tablo  ), dans l'action ?



    let panGesture: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "pointPan:")

    pour n'avoir qu'une fonction



    func pointPan(recognizer: UIPanGestureRecognizer, le Point Associée )

    qui s'appliquera au point reçu


  • samirsamir Membre

    Hello,


     


    Il faudra que tu crées des structures/classes pour modéliser tes données ( les curves) et enduites tu passera en paramètres cette structure/classe pour ta fonction générique. 

  • AliGatorAliGator Membre, Modérateur
    C'est fait comment ta vue ?
    - Chaque point bleu est une UIView, et chacune de ces view a son propre UIPanGestureRecognizer ?
    - Ou tu as une seule grande vue (celle au fond jaune) dans laquelle tu dessines tout (tes poignées bleues et ta courbe) dans un seul drawRect ? (mais dans ce cas pourquoi avoir plusieurs UIPanGestureRecognizer sur la même vue ?)
    - Ou encore chaque point bleu est un CAShapeLayer, ainsi que la courbe rouge elle-même, et tous ces CALayer sont ajoutés à  une unique vue ?

    Dans tous les cas si c'est une seule UIView c'est plus logique d'avoir un seul UIPanGestureRecognizer (avoir plusieurs PanGestureRecognizer sur la même vue c'est pas forcément une bonne idée.
    Mais si c'est le premier cas, avec plusieurs vues et chacune n'ayant qu'un PanGR , alors je comprend mieux la question et on peut alors effectivement débattre ;)
  • Chaque point bleu est une instance de de la classe (UIView) Point qui a son drawrect (ovalInRect)



    pointStart = Point(frame: CGRectMake(pointStartX,pointStartY,8,8))
    self.view.addSubview(pointStart) 

    et j'ai mis pour l'instant un UIPanGestureRecognizer sur chacun des 4 points bleus.


  • Joanna CarterJoanna Carter Membre, Modérateur
    C'est plus "normal" à  utiliser un gesture recogniser sur la vue principale et utiliser la location de touche pour déterminer quelle sous-vue à  modifier
  • AliGatorAliGator Membre, Modérateur
    mars 2015 modifié #8
    Je sais pas Joanna, les deux solutions (un PanGR par UIView Point vs. un seul PanGR sur la vue jaune) se valent je pense.
    Le travail de détecter quelle vue est sous le point tapé est déjà  fait quand le PanGR est associé à  la UIView donc c'est dommage de le faire soi-même.

    Moi je ferrais un UIPanGR par UIView, comme c'est le cas, et mettrais le UIViewController en delegate de tous. Et ensuite je regarderais quel est le tapGR.view et pourrais donc en déduire quel est le point qui a été tapé. Comme ça ça fait le boulot de détection de "quelle vue est tapée" pour toi.
  • Ouais, je suis partant pour un UIPanGR sur chaque UIView, mais j'ai pas trop compris 



     


     


    et mettrais le UIViewController en delegate de tous
  • AliGatorAliGator Membre, Modérateur
    Pardon je voulais pas dire delegate, je voulais dire target

    Autrement dit que chaque UIPanGR appelle la même méthode de target/action. Tu n'auras donc qu'une seule méthode "-(void)handleTap:(UIPanGestureRecognizer*)panGR", certainement implémentée dans ton UIViewController parent contenant tout ce beau monde (ta vue jaune et tes vues bleues et tout), et tous tes UIPanGR appelleront cette même méthode.
  • C'est ce que je vais faire.


     


    Mais comment envoyer le paramètre de la UIView qui reçoit le GestureRecognizer, dans l'action ?


    Pour détecter quelle view (quel point bleu) je fais bouger.


  • AliGatorAliGator Membre, Modérateur
    Pourquoi vouloir la passer? Le GestureRecognizer la connait déjà ...

    - (void)handlePan:(UIPanGestureRecognizer*)panGR
    {
    UIView* tappedView = panGR.view;
    ...
    }
  • busterTheobusterTheo Membre
    mars 2015 modifié #13

    Je me suis rendu compte de ça.


     


    Voilà  ce que j'ai lorsque je fais un println(pan) :


     



     


    <UIPanGestureRecognizer: 0x78f9ec40; state = Began; view = <Mask08.Point 0x78f9dc20>; target= <(action=pointStartPan:, target=<Mask08.ViewController 0x78e5aee0>)>>



     


    Mais comment faire le test ?


     


    J'ai tout essayé :



    let tappedView = pan.view
    if tappedView == "pointStart" {
    println(tappedView)
    }

    Ou



    let tappedView = pan.view
    if tappedView == "<Mask08.Point 0x78f9dc20>" {
    println(tappedView)
    }

    Ou



    let tappedView = pan.view
    if tappedView == "0x78f9dc20" {
    println(tappedView)
    }

    Avec plus haut



    var pointStart: Point!

    Point : La classe UIView qui fait des points.


    pointStart, l'instance - Un point bleu


  • J'ai parcouru avec plaisir ce post, et ça m'a permis de mieux préciser ma question.


     


    En fait, la difficulté réside dans le fait que chaque (func pointStartPan(recognizer: UIPanGestureRecognizer)), fait des choses différentes. Par ex, si je déplace un point (bleu) de simulation de point de contrôle, je dois aussi modifier le point de contrôle associé sur la courbe. Et pour chaque point (bleu), c'est différent.


     


    Je dois donc pouvoir faire un test sur la UIView tapped, et donc pouvoir l'identifier.


  • AliGatorAliGator Membre, Modérateur

    J'ai tout essayé :


    let tappedView = pan.view
    if tappedView == "pointStart" {
    println(tappedView)
    }

    Ou

    let tappedView = pan.view
    if tappedView == "<Mask08.Point 0x78f9dc20>" {
    println(tappedView)
    }

    Ou

    let tappedView = pan.view
    if tappedView == "0x78f9dc20" {
    println(tappedView)
    }
    Oula tu me fais peur là  c'est quoi ce code ? Tu compares une UIView avec une String ???!

    Je suis étonné que le compilateur Swift ne t'aie pas gueulé dessus, ca n'a pas de sens ce sont deux types qui n'ont rien a voir... comprends-tu ce que tu fais quand tu écris ce genre de code ?!
  • busterTheobusterTheo Membre
    mars 2015 modifié #16
    Je sais, et j'ai fait aussi avec "as? String" - Donc pas de crash - En fait, je veux récupérer le nom de la View, et pour moi, cela ne peut qu'être une String - J'ai essayé aussi "view.name", ça n'existe pas.
     
    Désolé d'avoir l'air neuhneuh, mais je suis ma piste. C'est pas toujours facile de bien communiquer - En gros je veux le nom de la view tapped.
     
    Mais finalement, tout ça, c'est juste pour éviter, en fait, d'avoir 4 "func[/size] unPoint(recognizer: [/size]UIPanGestureRecognizer[/size])[/size]", et je me rend compte que c'est débile. En fait, je suis en train de me rendre compte que ma forme complète devrait être faite à  partir d'une classe qui englobe les courbes et les points (eux aussi des classes UIView), et les 4 gestureRecognizer pour chaque forme, mais le problème est que , ces courbes et ces points ne peuvent pas être dans la même view, pour permettre aux points de s'afficher en dehors du masque, et pour permettre l'opération de masking sur seulement une partie de la forme complète.
     
    Donc une ou quatre function de GestureRecognizer, c'est plus le sujet, ce serait plutôt de monter une classe de forme complète avec ce problème de masque et de points en dehors du masque. Je crois que je ne peux pas faire une classe de cette forme.
     
    Voici une vidéo
     
    C'est une forme, mais j'aurais ensuite en gros 8 à  10 formes
  • busterTheobusterTheo Membre
    mars 2015 modifié #17

    Bon, j'ai monté une classe Dent qui implémente les classes Curve et Point


     


    Et je met deux Dents dans la self.view


     


    vidéo


     


    ça marche pas mal, à  part les bugs


    J'ai deux dents, et les gestureRecognizer et les UIScrollView se chevauchent, et certaines poignées ne sont plus accessibles.


     


    Voici le code


     


    ViewController



    import UIKit

    class ViewController: UIViewController {

    // Mark: - Les objets

    var dent: Dent!
    var dent2: Dent!

    override func viewDidLoad() {
    super.viewDidLoad()

    dent = Dent(frame: CGRectMake(262, 134, 500, 500))
    self.view.addSubview(dent)


    dent2 = Dent(frame: CGRectMake(462, 134, 500, 500))
    self.view.addSubview(dent2)
    }
    }

    Et Dent, qui fait Curve et Point (qui font les drawRect), et qui gère (Dent) les gestureRecognizer



    import UIKit

    class Dent: UIView, UIScrollViewDelegate {

    // Mark: - Les objets

    var aCurve: Curve!

    var pointStart: Point!
    var pointP1: Point!
    var pointEnd: Point!
    var pointP2: Point!

    var myView: UIView!
    var myScrollView:UIScrollView = UIScrollView()

    var myImageView = UIImageView()

    // Mark: - Les variables

    var startCurveX = CGFloat(100)
    var startCurveY = CGFloat(200)
    var aCurveP1X = CGFloat(100)
    var aCurveP1Y = CGFloat(350)

    var aEndCurveX = CGFloat(200)
    var aEndCurveY = CGFloat(200)
    var aCurveP2X = CGFloat(200)
    var aCurveP2Y = CGFloat(350)

    var pointStartX = CGFloat(96)
    var pointStartY = CGFloat(200)
    var pointP1X = CGFloat(96)
    var pointP1Y = CGFloat(350)

    var pointEndX = CGFloat(196)
    var pointEndY = CGFloat(200)
    var pointP2X = CGFloat(196)
    var pointP2Y = CGFloat(350)


    var bCurveP1X = CGFloat(190)
    var bCurveP1Y = CGFloat(50)

    var bCurveP2X = CGFloat(100)
    var bCurveP2Y = CGFloat(50)
    var bEndCurveX = CGFloat(100)
    var bEndCurveY = CGFloat(200)


    override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()

    // LA VIEW ENGLOBANTE
    myView = UIView(frame: CGRectMake(0, 0, 500, 500))
    self.addSubview(myView)

    // LA SCROLLVIEW QUI CONTIENT LA IMAGEVIEW
    myScrollView.delegate = self
    myScrollView.frame = CGRectMake(0, 0, 500, 500)
    myView.addSubview(myScrollView)

    // LA IMAGEVIEW DE LA PHOTO
    let myImage = UIImage(named: "moi.jpg")!
    myImageView.image = myImage
    myImageView.contentMode = UIViewContentMode.Center
    myImageView.frame = CGRectMake(0, 0, myImage.size.width, myImage.size.height)
    myScrollView.contentSize = myImage.size
    myImageView.userInteractionEnabled = true
    myScrollView.addSubview(myImageView)

    myScrollView.minimumZoomScale = 1
    myScrollView.maximumZoomScale = 8
    myScrollView.zoomScale = 1

    // LA FORME DU MASQUE
    aCurve = Curve(frame: CGRectMake(0, 0,500,500))
    myView.addSubview(aCurve)

    // Actuallisation des coordonnées des points
    aCurve.startCurveFloatX = startCurveX
    aCurve.startCurveFloatY = startCurveY

    aCurve.aCurveP1FloatX = aCurveP1X
    aCurve.aCurveP1FloatY = aCurveP1Y
    aCurve.aCurveP2FloatX = aCurveP2X
    aCurve.aCurveP2FloatY = aCurveP2Y

    aCurve.aEndCurveFloatX = aEndCurveX
    aCurve.aEndCurveFloatY = aEndCurveY

    aCurve.bCurveP1FloatX = bCurveP1X
    aCurve.bCurveP1FloatY = bCurveP1Y
    aCurve.bCurveP2FloatX = bCurveP2X
    aCurve.bCurveP2FloatY = bCurveP2Y

    aCurve.bEndCurveFloatX = bEndCurveX
    aCurve.bEndCurveFloatY = bEndCurveY

    // LES POINTS BLEUS
    pointStart = Point(frame: CGRectMake(pointStartX,pointStartY,8,8))
    self.addSubview(pointStart)

    pointEnd = Point(frame: CGRectMake(pointEndX,pointEndY,8,8))
    self.addSubview(pointEnd)

    pointP1 = Point(frame: CGRectMake(pointP1X,pointP1Y,8,8))
    self.addSubview(pointP1)

    pointP2 = Point(frame: CGRectMake(pointP2X,pointP2Y,8,8))
    self.addSubview(pointP2)


    // LE MASKING
    myView.maskView = aCurve


    // Le pan du pointStart
    let panGesturePointStart: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "pointStartPan:")
    panGesturePointStart.maximumNumberOfTouches = 1
    panGesturePointStart.minimumNumberOfTouches = 1
    pointStart.addGestureRecognizer(panGesturePointStart)
    pointStart.userInteractionEnabled = true

    // Le pan du pointEnd
    let panGesturePointEnd: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "pointEndPan:")
    panGesturePointEnd.maximumNumberOfTouches = 1
    panGesturePointEnd.minimumNumberOfTouches = 1
    pointEnd.addGestureRecognizer(panGesturePointEnd)
    pointEnd.userInteractionEnabled = true

    // Le pan du premier point de contrôle - pointP1
    let panGesturepointP1: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "pointP1Pan:")
    panGesturepointP1.maximumNumberOfTouches = 1
    panGesturepointP1.minimumNumberOfTouches = 1
    pointP1.addGestureRecognizer(panGesturepointP1)
    pointP1.userInteractionEnabled = true

    // Le pan du premier second de contrôle - pointP2
    let panGesturepointP2: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "pointP2Pan:")
    panGesturepointP2.maximumNumberOfTouches = 1
    panGesturepointP2.minimumNumberOfTouches = 1
    pointP2.addGestureRecognizer(panGesturepointP2)
    pointP2.userInteractionEnabled = true
    }

    required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    // Mark: - PanGestureRecognizer

    // PanGestureRecognizer du pointStart
    func pointStartPan(recognizer: UIPanGestureRecognizer) {
    let pan = recognizer as UIPanGestureRecognizer

    switch(pan.state) {
    case .Began:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat
    case .Changed:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP1.frame.origin.x = pointP1.frame.origin.x + recognizerX - pointStart.frame.origin.x
    pointP1.frame.origin.y = pointP1.frame.origin.y + recognizerY - pointStart.frame.origin.y

    pointStart.frame.origin.x = recognizerX
    pointStart.frame.origin.y = recognizerY

    aCurve.startCurveFloatX = recognizerX + startCurveX - pointStartX
    aCurve.startCurveFloatY = recognizerY + startCurveY - pointStartY

    aCurve.aCurveP1FloatX = pointP1.frame.origin.x + aCurveP1X - pointP1X
    aCurve.aCurveP1FloatY = pointP1.frame.origin.y + aCurveP1Y - pointP1Y


    aCurve.setNeedsDisplay()

    case .Ended:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointStart.frame.origin.x = recognizerX
    pointStart.frame.origin.y = recognizerY
    default:
    break
    }
    }

    // PanGestureRecognizer du pointEnd
    func pointEndPan(recognizer: UIPanGestureRecognizer) {
    let pan = recognizer as UIPanGestureRecognizer

    switch(pan.state) {
    case .Began:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat
    case .Changed:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP2.frame.origin.x = pointP2.frame.origin.x + recognizerX - pointEnd.frame.origin.x
    pointP2.frame.origin.y = pointP2.frame.origin.y + recognizerY - pointEnd.frame.origin.y

    pointEnd.frame.origin.x = recognizerX
    pointEnd.frame.origin.y = recognizerY

    aCurve.aEndCurveFloatX = recognizerX + aEndCurveX - pointEndX
    aCurve.aEndCurveFloatY = recognizerY + aEndCurveY - pointEndY

    aCurve.aCurveP2FloatX = pointP2.frame.origin.x + aCurveP2X - pointP2X
    aCurve.aCurveP2FloatY = pointP2.frame.origin.y + aCurveP2Y - pointP2Y


    aCurve.setNeedsDisplay()

    case .Ended:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointEnd.frame.origin.x = recognizerX
    pointEnd.frame.origin.y = recognizerY
    default:
    break
    }
    }

    // PanGestureRecognizer du pointP1
    func pointP1Pan(recognizer: UIPanGestureRecognizer) {
    let pan = recognizer as UIPanGestureRecognizer

    switch(pan.state) {
    case .Began:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat
    case .Changed:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP1.frame.origin.x = recognizerX
    pointP1.frame.origin.y = recognizerY

    aCurve.aCurveP1FloatX = pointP1.frame.origin.x + aCurveP1X - pointP1X
    aCurve.aCurveP1FloatY = pointP1.frame.origin.y + aCurveP1Y - pointP1Y

    aCurve.setNeedsDisplay()

    case .Ended:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP1.frame.origin.x = recognizerX
    pointP1.frame.origin.y = recognizerY
    default:
    break
    }
    }

    // PanGestureRecognizer du pointP2
    func pointP2Pan(recognizer: UIPanGestureRecognizer) {
    let pan = recognizer as UIPanGestureRecognizer

    switch(pan.state) {
    case .Began:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat
    case .Changed:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP2.frame.origin.x = recognizerX
    pointP2.frame.origin.y = recognizerY

    aCurve.aCurveP2FloatX = pointP2.frame.origin.x + aCurveP2X - pointP2X
    aCurve.aCurveP2FloatY = pointP2.frame.origin.y + aCurveP2Y - pointP2Y

    aCurve.setNeedsDisplay()


    case .Ended:
    let recognizerX = recognizer.locationInView(self).x as CGFloat
    let recognizerY = recognizer.locationInView(self).y as CGFloat

    pointP2.frame.origin.x = recognizerX
    pointP2.frame.origin.y = recognizerY
    default:
    break
    }
    }

    func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
    return myImageView
    }
    }

  • Joanna CarterJoanna Carter Membre, Modérateur

    Très mauvaise idée de faire une vue qui est aussi délégué d'une UIScrollView. Trop de répétition de code.  >:(


  • Ah mince,


    comment je fais pour mettre une UIScrollView dans chaque UIView ?


Connectez-vous ou Inscrivez-vous pour répondre.