web-dev-qa-db-fra.com

iOS - transmettre toutes les touches via une vue

J'ai une vue superposée sur beaucoup d'autres vues. J'utilise uniquement l'outil Overaly pour détecter un certain nombre de touches sur l'écran, mais je ne souhaite pas que la vue arrête le comportement des autres vues situées en dessous, qui sont des vues à défilement, etc. Comment transférer toutes les touches via cette vue de superposition? C'est un sous-réseau d'UIView.

124
sol

Pour passer des contacts d'une vue de superposition aux vues situées en dessous, implémentez la méthode suivante dans UIView:

Objectif c:

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

Rapide:

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
}
104
PixelCloudSt
myWebView.userInteractionEnabled = NO;

était tout ce dont j'avais besoin!

99
rmp251

C'est un vieux fil, mais il est apparu lors d'une recherche, alors j'ai pensé ajouter mon 2c. J'ai un UIView couvrant avec des sous-vues et je veux seulement intercepter les touches qui touchent l'une des sous-vues. J'ai donc 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;
}
51
fresidue

Version améliorée de la réponse @fresidue. Vous pouvez utiliser cette sous-classe UIView comme une vue transparente qui passe en dehors de sa sous-vue. Implémentation 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 dans 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)
    })
  }
}
32
Timur Bernikovich

Si la vue à laquelle vous souhaitez transférer les contacts ne correspond pas à une sous-vue/vue, vous pouvez définir une propriété personnalisée dans votre sous-classe UIView de la manière suivante:

@interface SomeViewSubclass : UIView {

    id forwardableTouchee;

}
@property (retain) id forwardableTouchee;

Assurez-vous de le synthétiser dans votre fichier .m:

@synthesize forwardableTouchee;

Et incluez ensuite les éléments suivants dans l’une de vos méthodes 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 sur la vue vers laquelle vous souhaitez que les événements soient transférés:

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

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

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

Ce que j'ai fait est de créer une sous-classe de UIStackView avec une propriété définissant la sous-vue qui devrait être touchable. Désormais, les touches des boutons latéraux (incluses dans le tableau * viewsWithActiveTouch *) seront affectées aux boutons, tandis que les touches de la vue de pile empilées ailleurs que ces vues ne seront pas interceptées, et donc transmises à tout ce qui se trouve sous la pile. vue.

/** 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
   }
}
5
Frédéric Adda

Dans Swift 5

class ThroughView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        guard let slideView = subviews.first else {
            return false
        }

        return slideView.hitTest(convert(point, to: slideView), with: event) != nil
    }
}
2
onmyway133

Essayez quelque chose comme ça ...

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

Le code ci-dessus, dans votre méthode touchesBegan par exemple, transmettrait les touches à toutes les sous-vues de la vue.

0
Jordan