4 votes

Sous-classe UIControl - Événements appelés deux fois

Je travaille actuellement sur une sous-classe personnalisée de UIControl. Pour suivre les touches, j'utilise la méthode suivante :

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
 NSLog(@"Start");
 CGPoint location = [touch locationInView:self];
 if ([self touchIsInside:location] == YES) {
    //Touch Down
    [self sendActionsForControlEvents:UIControlEventTouchDown];
    return YES;
 }
 else {
    return NO;
 }  
}

Cela fonctionne comme prévu et @"Start" est enregistré exactement une fois. L'étape suivante consiste à ajouter une cible et un sélecteur avec UIControlEventTouchDown.

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

Cela fonctionne également et la méthode action : est appelée. Mais c'est là que se situe mon problème. L'action est appelée deux fois. Qu'est-ce que je fais de mal ? J'utilise simplement [self sendActionsForControlEvents:UIControlEventTouchDown]; une fois et l'action cible est appelée deux fois. Quel est le problème avec mon code ?

Sandro Meier

11voto

Dad Points 3898

Le premier appel à la méthode d'action est effectué automatiquement par le répartiteur d'événements une fois que vous avez appelé :

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

pour enregistrer le gestionnaire.

Donc quand vous appelez ensuite :

//Touch Down
[self sendActionsForControlEvents:UIControlEventTouchDown];

vous générez le deuxième appel à votre gestionnaire (et à tous les autres qui sont connectés).

Il semble donc que vous n'ayez pas besoin à la fois du gestionnaire d'action et du beginTracking - utilisez l'un ou l'autre.

Mise à jour :

Compte tenu de votre commentaire et d'une réflexion plus approfondie : puisque vous êtes une sous-classe de UIControl, je pense que vous ne voulez probablement pas enregistrer des gestionnaires d'événements pour vous-même.

Au lieu de cela, vous devez utiliser exclusivement :

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)cancelTrackingWithEvent:(UIEvent *)event;   // event may be nil if cancelled for non-event reasons, e.g. removed from window

De même, le tracking variable d'instance.

Je pense donc que vous ne devriez pas afficher les événements ou écouter les événements. De plus, est-il réellement possible d'obtenir un événement beginTrackingWithTouch s'il n'est pas dans votre vue ? Il ne semble pas que ce soit possible. Je ne pense donc pas que vous ayez besoin de faire des tests pour savoir si elle se trouve dans votre vue.

Je pense donc que cela vaut la peine de prendre du recul et de réfléchir à ce que vous essayez de faire et de relire la documentation de UIControl. Plus précisément :

Notes sur la sous-classification Vous pouvez vouloir étendre une sous-classe de UIControl pour l'une des deux raisons suivantes :

Observer ou modifier l'envoi de messages d'action aux cibles pour des événements particuliers Pour ce faire, il faut remplacer sendAction:to:forEvent: , évalue le sélecteur transmis, l'objet cible ou le UIControlEvents bit et procédez comme requis.

Pour fournir un comportement personnalisé en matière de suivi (par exemple, pour modifier l'indicateur l'apparence de la surbrillance). Pour ce faire, modifiez une ou toutes les méthodes suivantes méthodes : beginTrackingWithTouch:withEvent: , continueTrackingWithTouch:withEvent: , endTrackingWithTouch:withEvent: .

La première partie est pour avoir votre UIControl permet une gestion non standard du traitement des actions cibles pour les clients ou les utilisateurs de votre contrôle (cela ne ressemble pas à ce que vous essayez de faire, bien que vous n'ayez pas vraiment donné une description de haut niveau).

La deuxième partie ressemble plus à ce que vous voulez faire - un suivi personnalisé dans votre site Web. UIControl sous-classe.

0voto

AndroidonEarth Points 11

J'ai également eu ce même problème. Lorsque j'enregistrais une action avec

[button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchDown];

la méthode d'action n'est déclenchée qu'une seule fois, mais lorsque je l'enregistre avec la méthode

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

la méthode d'action serait déclenchée deux fois.

La chose qui l'a résolu pour moi était de s'assurer que mon - (void) action: retour de la méthode IBAction au lieu de void . Je ne suis pas sûr de savoir pourquoi cela a semblé régler le problème.

-1voto

beryllium Points 18138

Hm Vérifiez mon code pour vos objectifs :

UIContr.h

@interface UIContr : UIControl {

}

@end

UIContr.m

#import "UIContr.h"
@implementation UIContr
- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code.
    }
    return self;
}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"Start");
    CGPoint location = [touch locationInView:self];
    if (CGRectContainsPoint(self.frame, location)) {
        //Touch Down
        [self sendActionsForControlEvents:UIControlEventTouchDown];
        return YES;
    }
    else {
        return NO;
    }  
}

- (void)dealloc {
    [super dealloc];
}
@end

Comment l'utiliser dans UIViewController :

- (void)viewDidLoad {
    UIContr *c = [[UIContr alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
    [c addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
    c.backgroundColor = [UIColor redColor];
    [self.view addSubview:c];
}

-(void)action:(id)sender{
    NSLog(@"123");
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X