iOS - transférer toutes les touches à travers une vue


75

J'ai une vue superposée sur de nombreuses autres vues. J'utilise seulement le overaly pour détecter un certain nombre de touches sur l'écran, mais à part ça je ne veux pas que la vue arrête le comportement des autres vues en dessous, qui sont scrollviews, etc. Comment puis-je transmettre toutes les touches à travers cette vue de superposition? C'est un sous-ensemble de UIView.

0

Essayez quelque chose comme ça ...

for (UIView *view in subviews) 
    [view touchesBegan:touches withEvent:event]; 

Le code ci-dessus, dans votre méthode de touchesBegan par exemple passeraient la touche à tous les sous-vues de vue.

+6

Le problème avec ce AFAIK approche est que tenter de transmettre des touches aux classes de cadre UIKit aura le plus souvent pas effet. Selon la documentation d'Apple, les classes d'infrastructure UIKit ne sont pas conçues pour recevoir des contacts dont la propriété view est définie sur une autre vue. Donc, cette approche fonctionne principalement pour les sous-classes personnalisées de UIView. 02 mars. 112011-03-02 23:05:35


4

Si la vue que vous souhaitez transférer la touche à ne pas arriver à être un sous-vue/superview, vous pouvez configurer une propriété personnalisée dans votre sous-classe UIView comme ceci:

@interface SomeViewSubclass : UIView { 

    id forwardableTouchee; 

} 
@property (retain) id forwardableTouchee; 

Assurez-vous de faire la synthèse dans votre .m:

@synthesize forwardableTouchee; 

Et puis inclure ce qui suit dans l'un de vos méthodes de UIResponder telles que:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

    [self.forwardableTouchee touchesBegan:touches withEvent:event]; 

} 

Où que vous instanciez votre UIView, définissez la propriété forwardableTouchee à quelque vue que vous souhaitez les événements à transmettre à:

SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease]; 
    view.forwardableTouchee = someOtherView; 

75

Pour passer des touches d'une vue de superposition des vues en dessous, mettre en œuvre la méthode suivante le UIView:

Objective-C:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 
    NSLog(@"Passing all touches to the next view (if any), in the view stack."); 
    return NO; 
} 

Swift:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
    print("Passing all touches to the next view (if any), in the view stack.") 
    return false 
} 
+2

J'ai le même problème, mais ce que je veux, c'est que si je suis en train de zoomer/tourner/déplacer la vue avec le geste, il devrait retourner oui et pour l'événement de repos il devrait retourner non, comment puis-je y arriver? 12 août. 132013-08-12 06:27:33


58
myWebView.userInteractionEnabled = NO; 

était tout ce dont j'avais besoin!


38

Ceci est un ancien fil, mais il est venu sur une recherche, alors j'ai pensé que j'ajouterais mon 2c. J'ai un UIView de couverture avec des sous-vues, et que vous souhaitez que d'intercepter les touches qui ont frappé l'un des sous-vues, donc je modifié la réponse de PixelCloudSt à

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    for (UIView* subview in self.subviews) { 
     if ([subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil) { 
      return YES; 
     } 
    } 
    return NO; 
} 
+1

Vous devez créer une sous-classe UIView personnalisée (ou une sous-classe de toute autre sous-classe UIView telle que UIImageView ou autre) et remplacer cette fonction. En substance, la sous-classe peut avoir une '@interface' entièrement vide dans le fichier .h, et la fonction ci-dessus doit être le contenu entier de '@implementation'. 07 mars. 142014-03-07 16:01:14


-1

Comme suggéré par @PixelCloudStv si vous voulez jeter touché d'une vue à une autre, mais avec un contrôle supplémentaire sur ce processus - sous-classe UIView

// tête

@interface TouchView : UIView 

@property (assign, nonatomic) CGRect activeRect; 

@end 

// mise en œuvre

Après

Après dans interfaceBuilder, il suffit de définir la classe de View à TouchView et de définir rect rect actif avec votre rect. Vous pouvez également changer et implémenter une autre logique.


3

J'ai eu un problème similaire avec un UIStackView (mais pourrait être n'importe quelle autre vue). Ma configuration est la suivante: View controller with containerView and StackView

Il est un cas classique où j'ai un conteneur qui devait être placé en arrière-plan, avec des boutons sur le côté. Pour la mise en page, j'ai inclus les boutons dans un UIStackView, mais maintenant la partie centrale (vide) du stackView intercepte les touches :-(

Ce que j'ai fait est de créer une sous-classe de UIStackView avec une propriété définissant le subView qui devrait être touchable Maintenant, tout toucher sur les boutons latéraux (inclus dans le tableau * viewsWithActiveTouch *) sera donné aux boutons, tandis que tout toucher sur la pileview ailleurs que dans ces vues ne sera pas intercepté, et donc transmis à tout ce qui est sous la vue de la pile.

/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */ 
class NoTouchStackView: UIStackView { 

    var viewsWithActiveTouch: [UIView]? 

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 

    if let activeViews = viewsWithActiveTouch { 
     for view in activeViews { 
      if CGRectContainsPoint(view.frame, point) { 
       return view 

      } 
     } 
    } 
    return nil 
    } 
} 

14

version améliorée de réponse @fresidue. Vous pouvez utiliser cette sous-classe UIView en vue transparente passant des touches òû côté de sa sous-vue. La mise en œuvre dans Objective-C:

@interface PassthroughView : UIView 

@end 

@implementation PassthroughView 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    for (UIView *view in self.subviews) { 
     if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) { 
      return YES; 
     } 
    } 
    return NO; 
} 

@end 

et Swift:

class PassthroughView: UIView { 
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
    return subviews.contains(where: { 
     !$0.isHidden && $0.point(inside: self.convert(point, to: $0), with: event) 
    }) 
    } 
}