web-dev-qa-db-fra.com

Les cibles UIButton ne fonctionnent pas si un UIView est ajouté en tant que sous-vue

J'ai un UIButton. Il a deux sous-vues. J'appelle alors:

[createButton addTarget:self action:@selector(openComposer) forControlEvents:UIControlEventTouchUpInside];

Si je tape sur les parties de la variable UIButton qui ne sont pas couvertes mais dans l'une de ses sous-vues, cela fonctionne correctement. Cependant, si j'appuie sur l'une des sous-vues, l'action ne sera pas déclenchée.

Sur les deux sous-vues, .userInteractionEnabled est défini sur YES.

Les deux sous-vues sont des UIViewss simples avec frame et backgroundColor.

Comment puis-je obtenir le robinet pour "passer à travers" le UIView et sur le UIButton?

Merci

EDIT: Je dois utiliser UIControlEvents car j'ai besoin de UIControlEventTouchDown.

EDIT 2:

Voici le code pour le bouton.

@interface CreateButton ()

@property (nonatomic) Theme *theme;
@property (nonatomic) UIView *verticle;
@property (nonatomic) UIView *horizontal;
@property (nonatomic) BOOL mini;

@end

@implementation CreateButton

#pragma mark - Accessors

- (UIView *)verticle {
    if (! _verticle) {
        _verticle = [[UIView alloc] init];
        _verticle.backgroundColor = [self.theme colorForKey:@"createButtonPlusBackgroundColor"];
        _verticle.userInteractionEnabled = NO;
    }
    return _verticle;
}

- (UIView *)horizontal {
    if (! _horizontal) {
        _horizontal = [[UIView alloc] init];
        _horizontal.backgroundColor = [self.theme colorForKey:@"createButtonPlusBackgroundColor"];
        _verticle.userInteractionEnabled = NO;
    }
    return _horizontal;
}

#pragma mark - Init

- (instancetype)initWithTheme:(Theme *)theme frame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _theme = theme;

        self.layer.cornerRadius = roundf(frame.size.width / 2);
        self.layer.shadowColor = [UIColor blackColor].CGColor;
        self.layer.shadowOpacity = .1f;
        self.layer.shadowOffset = CGSizeZero;
        self.layer.shadowRadius = 15.f;
        self.backgroundColor = [self.theme colorForKey:@"createButtonBackgroundColor"];

        [self addSubview:self.verticle];
        [self addSubview:self.horizontal];

        [self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchDown];
        [self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchUpInside];
        [self addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchUpOutside];
    }
    return self;
}

#pragma mark - Actions

- (void)animate {
    [UIView animateWithDuration:0.2 delay:0 usingSpringWithDamping:0.4 initialSpringVelocity:8 options:kNilOptions animations:^{
        if (self.mini) {
            self.transform = CGAffineTransformMakeScale(1.0, 1.0);
            self.mini = NO;
        } else {
            self.transform = CGAffineTransformMakeScale(0.90, 0.90);
            self.mini = YES;
        }
    } completion:nil];
}

#pragma mark - UIView

- (void)layoutSubviews {
    CGSize size = self.bounds.size;

    NSInteger width = 3;
    NSInteger verticleInset = 12;
    self.verticle.frame = CGRectMake((size.width - width) / 2, verticleInset, width, size.height - (verticleInset * 2));
    self.horizontal.frame = CGRectMake(verticleInset, (size.height - width) / 2, size.width - (verticleInset * 2), width);
}

@end
14
Jason Silberman

Définissez userInteractionEnabled sur NO pour que vos sous-vues permettent aux touches de passer au travers et sur votre bouton.

Assurez-vous également de changer _verticle.userInteractionEnabled = NO; dans votre lazy-loader pour votre propriété horizontal en _horizontal.userInteractionEnabled = NO; car je crois que c'est une faute de frappe.

30
TylerTheCompiler

veuillez utiliser le code comme ci-dessous (remplacez 'ViewControllerFilterCategory' par votre propre numéro + nom_nib) pour ajouter le contrôleur de nib (enfant) en tant que contrôleur enfant du contrôleur actuel avant d'ajouter la vue en tant que sous-vue. Ensuite, iOS appellera les actions attachées au contrôleur enfant comme prévu:

    let vcCats = ViewControllerFilterCategory(nibName: "ViewControllerFilterCategory", bundle: Bundle.main);
    self.addChildViewController(vcCats);
    self.view.addSubview(vcCats.view);

P.S. N'oubliez pas d'appeler 'removeFromParentViewController' avant de supprimer votre vue secondaire (comme ci-dessous):

@IBAction func onCanceled(_ sender: Any) {
    self.removeFromParentViewController()
    self.view.removeFromSuperview()
}
1
Mostafa Aghajani

J'ai fait face à ce problème.

Dans mon cas, j'avais nib chargé en tant que sous-vue.

UIViewController *vc = [[[NSClassFromString(@"nib_controller") alloc] initWithNibName:@"nib_name" bundle:nil] autorelease];
[self.view addSubview:vc.view];

Dans la vue nib (vc.view), tous les boutons n’appelaient pas l’action.

[(UIButton*)[self.view viewWithTag:button_tag] addTarget:self action:@selector(btnActions:) forControlEvents:UIControlEventTouchUpInside];


-(IBAction)btnActions:(id)sender{

    // list star buttons for bookmark
    NSLog(@"btnActions tag %d", [sender tag]);

    // bla bla bla
}

J'ai pu toucher les boutons, mais la méthode btnActions n'était pas déclenchée.

Ensuite, j'ai juste essayé quelque chose de très simple et logique.

Sur le contrôleur de vue parent, j'ai une méthode avec le même nom:

-(IBAction)btnActions:(id)sender{

    // list star buttons for bookmark
    NSLog(@"parent btnActions tag %d", [sender tag]);

    // bla bla bla
}

Je viens d'ajouter le NSLog à l'intérieur pour voir ce qui se passe. Le résultat est apparu sur la console du journal:

parent btnActions tag xxx

Cela n’était pas possible dans les versions précédentes d’iOS 9.

Mais maintenant, il est possible d’accéder aux méthodes à partir de la vue parent si la vue est chargée à partir de la vue du contrôleur nib.

Pour qui confond encore, voir l'illustration ci-dessous

parent -> A
enfant > B

----------
|        | 
|   A    |
|        |
----------
    |
    |--- -(IBAction)btnActions:(id)sender


----------
|        | 
|   B    |
|        |
----------
    |
    |--- -(IBAction)btnActions:(id)sender (the controller have an method with same name as parent)

Le B.view est ajouté à partir d'un contrôleur

----------
|        | 
|   A    |
|        |
----------
    |
    |--- (touching some button -> execute this:

UIViewController *B = [[[NSClassFromString(@"B_controller") alloc] initWithNibName:@"B_name" bundle:nil] autorelease];
[self.view addSubview:B.view]; // The B.view is added as subview.

Les boutons à l'intérieur de B.view envoient des actions à -(IBAction)btnActions

Échantillon

[(UIButton*)[self.view viewWithTag:button_tag] addTarget:self action:@selector(btnActions:) forControlEvents:UIControlEventTouchUpInside];

Tous les boutons semblent bien fonctionner car ils peuvent tous être touchés ou cliqués (simulateur xcode). Mais la méthode -(IBAction)btnActions déclarée dans B.controller n'était pas appelée. Je suis resté coincé à résoudre ce problème pendant de nombreuses heures jusqu'à ce que je réalise que les actions étaient envoyées au A.Controller, comme décrit ci-dessus.

Le problème, c’est que, dans les premières versions d’IOS, cela n’était pas possible.

Je ne suis pas sûr, mais d'après iOS9, nous avons ce comportement différent.

L'application fonctionnait bien jusqu'à iOS8.

0
Daniel Omine