2016-05-21 4 views
4

Imaginez un écran iOS où vous pouvez déplacer votre doigt haut/bas faire quelque chose (imaginez dire, « l'échelle »),Résumé de reconnaissance de geste à deux fonctions dans Swift?

Ou,

en fonction séparée, vous pouvez déplacer votre doigt gauche/droite pour faire quelque chose (imaginez dire, "changer de couleur" ou "tourner").

Ils sont

séparés

fonctions

, vous ne pouvez faire un à au moment. Donc, s'il "commence comme" une version horizontale, il reste seulement une version horizontale. Inversement, s'il "commence comme" une version verticale, il ne reste qu'une version verticale.

Il est un peu difficile à faire, je vous présente exactement comment le faire ci-dessous ... le modèle fondamental est:

if (r.state == .Began || panway == .WasZeros) 
    { 
    prev = tr 
    if (tr.x==0 && tr.y==0) 
     { 
     panway = .WasZeros 
     return 
     } 
    if (abs(tr.x)>abs(tr.y)) ... set panway 
    } 

Cela fonctionne très bien et est ici exactement comment le faire à Swift .

Dans le storyboard, prenez un UIPanGestureRecognizer, faites-le glisser vers la vue en question. Connectez le délégué au contrôleur de vue et mettre la sortie à cet appel ultraPan:

enum Panway 
    { 
    case Vertical 
    case Horizontal 
    case WasZeros 
    } 
var panway:Panway = .Vertical 
var prev:CGPoint! 

@IBAction func ultraPan(r:UIPanGestureRecognizer!) 
    { 
    let tr = r.translationInView(r.view) 

    if (r.state == .Began || panway == .WasZeros) 
     { 
     prev = tr 

     if (tr.x==0 && tr.y==0) 
      { 
      panway = .WasZeros 
      return 
      } 

     if (abs(tr.x)>abs(tr.y)) 
      { 
      panway = .Horizontal 
      } 
     else 
      { 
      panway = .Vertical 
      } 
     } 

    if (panway == .Horizontal) // your left-right function 
     { 
     var h = tr.x - prev.x 
     let sensitivity:CGFloat = 50.0 
     h = h/sensitivity 
     // adjust your left-right function, example 
     someProperty = someProperty + h 
     } 

    if (panway == .Vertical) // bigger/smaller 
     { 
     var v = tr.y - prev.y 
     let sensitivity:CGFloat = 2200.0 
     v = v/sensitivity 
     // adjust your up-down function, example 
     someOtherProperty = someOtherProperty + v 
     } 

    prev = tr 
    } 

C'est très bien.

Mais il serait sûrement préférable de faire une nouvelle sous-classe (ou quelque chose) de UIPanGestureRecognizer, afin qu'il y ait deux nouveaux concepts ......

UIHorizontalPanGestureRecognizer 

UIVerticalPanGestureRecognizer 

Ce serait essentiellement de un Panneaux dimensionnels.

Je n'ai absolument aucune idée si vous ... sous-classe les délégués? ou la classe? (Quelle classe?), Ou peut-être une sorte d'extension ... En effet, je suis fondamentalement complètement désemparés sur ce :)

L'objectif est dans un code de, vous pouvez avoir quelque chose comme ça ...

@IBAction func horizontalPanDelta(..?) 
    { 
    someProperty = someProperty + delta 
    } 
@IBAction func verticalPanDelta(..?) 
    { 
    otherProperty = otherProperty + delta 
    } 

Comment hériter/étendre UIPanGestureRecognizer de cette façon?

Répondre

3

Mais il serait certainement préférable de faire une nouvelle sous-classe (ou quelque chose) de UIPanGestureRecognizer, de sorte qu'il y ait deux nouveaux concepts ......

  • UIHorizontalPanGestureRecognizer

  • UIVerticalPanGestureRecognizer

Ceux-ci seraient fondamentalement un panniers unidimensionnels

Correct. C'est exactement comment le faire, et c'est l'approche normale. En effet, c'est exactement ce que les reconnaisseurs de gestes sont pour: chaque g.r. reconnaît seulement son geste propre, et quand il le fait, il provoque le recul des reconnaisseurs de gestes concurrents. C'est tout le point des reconnaisseurs de gestes! Sinon, nous serions encore de retour dans le pré-g.r. jours de pur touchesBegan et ainsi de suite (oh, l'horreur).

Mon livre en ligne discute, en fait, l'exemple très vous donnez ici:

http://www.apeth.com/iOSBook/ch18.html#_subclassing_gesture_recognizers

Et voici un exemple téléchargeable réel qu'il met en œuvre à Swift:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch05p203gestureRecognizers/ch18p541gestureRecognizers/HorizVertPanGestureRecognizers.swift

Observez la stratégie utilisée ici. Nous faisons des sous-classes UIPanGestureRecognizer. Nous surpassons touchesBegan et touchesMoved: au moment où la reconnaissance commence, nous échouons dès qu'il apparaît que le contact suivant est sur le mauvais axe. (Vous devriez regarder la vidéo d'Apple sur ce sujet, comme vous le dites, lorsque vous sous-classez un outil de reconnaissance de gestes, vous devriez "échouer tôt, échouer souvent".) translationInView Ainsi, seul le mouvement le long de l'axe est possible. Le résultat (comme vous pouvez le voir si vous téléchargez le projet lui-même) est une vue qui peut être déplacée horizontalement ou verticalement mais pas d'une autre manière.

2

@Joe, c'est quelque chose que j'ai brouillé ensemble rapidement pour le plaisir de cette question. Pour faciliter la réalisation, je lui ai simplement donné un rappel plutôt que de mettre en place un système de cibles-actions. N'hésitez pas à le changer.

enum PanDirection { 
    case Horizontal 
    case Vertical 
} 

class OneDimensionalPan: NSObject { 

    var handler: (CGFloat ->())? 
    var direction: PanDirection 

    @IBOutlet weak var panRecognizer: UIPanGestureRecognizer! { 
     didSet { 
      panRecognizer.addTarget(self, action: #selector(panned)) 
     } 
    } 

    @IBOutlet weak var panView: UIView! 

    override init() { 
     direction = .Horizontal 
     super.init() 
    } 

    @objc private func panned(recognizer: UIPanGestureRecognizer) { 
     let translation = panRecognizer.translationInView(panView) 
     let delta: CGFloat 
     switch direction { 
     case .Horizontal: 
      delta = translation.x 
      break 
     case .Vertical: 
      delta = translation.y 
      break 
     } 
     handler?(delta) 
    } 
} 

En story-board, faites glisser un UIPanGestureRecognizer sur votre contrôleur de vue, puis faites glisser un Object sur la barre supérieure du contrôleur de vue, définir sa classe, et relier ses IBOutlet s. Après cela, vous devriez être bon à faire. Dans votre code de contrôleur de vue, vous pouvez définir son rappel et sa direction de panoramique.

UPDATE EXPLICATION> Je veux préciser pourquoi je fait la classe une sous-classe de NSObject: l'idée motrice de la classe est de garder tout code inutile de la UIViewController. En sous-classant NSObject, je peux ensuite faire glisser un Object sur la barre supérieure du contrôleur de vue à l'intérieur du storyboard et définir sa classe sur OneDimensionalPan. De là, je suis en mesure de se connecter à @IBOutlet s. J'aurais pu en faire une classe de base, mais il aurait ensuite fallu l'instancier par programmation. C'est beaucoup plus propre. Le seul code à l'intérieur du contrôleur de vue est d'accéder à l'objet lui-même (via un @IBOutlet), de définir sa direction et de définir son rappel.

+0

@Joe, pour répondre à la question, s'il vous plaît donner une réponse quant à la façon dont il a résolu ou n'a pas résolu votre problème. –

+0

Bonjour @adamH. - de retour avec vous dès que possible! Je n'ai pas encore eu la chance .... – Fattie

+0

Je pensais juste que j'ajouterais que vous devrez peut-être utiliser la méthode déléguée du détecteur de mouvement pour les laisser reconnaître simultanément. –