2009-08-17 5 views
16

Je vais écrire mon propre contrôle personnalisé qui est très différent d'UIButton. C'est tellement différent que j'ai décidé de l'écrire à partir de zéro. Donc tout ce que je sous-classe est UIControl.Comment implémenter un mécanisme d'action-cible pour un contrôle personnalisé?

Lorsque mon contrôle est touché à l'intérieur, alors je veux déclencher un message en mode d'action-cible. L'utilisateur de cette classe peut l'instancier, puis ajouter des cibles et des actions pour cet événement.

Imaginez que j'appelle en interne une méthode -fireTargetsForTouchUpEvent. Comment pourrais-je maintenir ce mécanisme cible-action dans ma classe? Dois-je ajouter toutes les cibles et actions à mon propre tableau, puis appeler simplement les sélecteurs (les actions) sur les objets cibles dans une boucle for? Ou y a-t-il une manière plus intelligente de le faire? J'imagine fournir quelques méthodes pour ajouter des cibles et des actions pour certains événements comme cet événement de retouche (je le soulève manuellement en appelant une méthode interne quand cela arrive). Une idée?

+0

Généralement, les contrôles ont une cible, un sélecteur par événement. En veux-tu plus? –

+0

Pourrais-je en avoir plus, si je le voulais? Je pense que oui...mais pas sûr –

Répondre

5

Puisque vous avez l'intention de sous-classe UIControl, vous pouvez simplement utiliser

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents; 

Avec cela, une classe peut s'enregistrer comme une cible pour tous les événements qu'il veut sur votre contrôleur personnalisé.

13

Vous avez la bonne idée. Voici comment je le ferais:

@interface TargetActionPair : NSObject 
{ 
    id target; 
    SEL action; 
} 
@property (assign) id target; 
@property (assign) SEL action; 
+ (TargetActionPair *)pairWithTarget:(id)aTarget andAction:(SEL)selector; 
- (void)fire; 
@end 

@implementation TargetActionPair 
@synthesize target; 
@synthesize action; 

+ (TargetActionPair *)pairWithTarget:(id)aTarget andAction:(SEL)anAction 
{ 
    TargetActionPair * newSelf = [[self alloc] init]; 
    [newSelf setTarget:aTarget]; 
    [newSelf setAction:anAction]; 
    return [newSelf autorelease]; 
} 

- (void)fire 
{ 
    [target performSelector:action]; 
} 

@end 

Avec cette classe en place, le stockage de vos paires cible/d'action est assez simple:

MyCustomControl.h:

#import "TargetActionPair.h" 

@interface MyCustomControl : UIControl 
{ 
    NSMutableArray * touchUpEventHandlers; 
} 

- (id)init; 
- (void)dealloc; 

- (void)addHandlerForTouchUp:(TargetActionPair *)handler; 

@end 

MyCustomControl .m:

#import "TargetActionPair.h" 

@implementation MyCustomControl 

- (id)init 
{ 
    if ((self = [super init]) == nil) { return nil; } 
    touchUpEventHandlers = [[NSMutableArray alloc] initWithCapacity:0]; 
    return self; 
} 

- (void)dealloc 
{ 
    [touchUpEventHandlers release]; 
} 

- (void)addHandlerForTouchUp:(TargetActionPair *)handler 
{ 
    [touchUpEventHandlers addObject:handler]; 
} 

- (void) fireTargetsForTouchUpEvent 
{ 
    [touchUpEventHandlers makeObjectsPerformSelector:@selector(fire)]; 
} 

@end 

Après cela, la mise en place du contrôle serait fait comme suit:

[instanceOfMyControl addHandlerForTouchUp: 
     [TargetActionPair pairWithTarget:someController 
           andAction:@selector(touchUpEvent)]; 
+0

wow, la plus grande réponse que j'ai jamais eu ici;) merci! Pour mon cas, j'ai compris qu'UIControl semblait m'offrir déjà ce dont j'avais besoin. Mais quand il y a des événements spéciaux à traiter, votre technique est excellente! –

+0

En fait, pour les événements personnalisés, vous pouvez utiliser les bits UIControlEventApplicationReserved (16 disponibles) et call - (void) sendActionsForControlEvents: (UIControlEvents) controlEvents; – Felixyz

+0

Ce qui manque ici est un moyen de supprimer une cible/action et peut-être un contrôle en double. – pixelfreak

38

Je veux juste clarifier ce que @Felixyz a dit parce que ce n'était pas clair pour moi au début.

Si vous sous-classes UIControl, même si vous allez avoir un événement personnalisé, vous n'avez pas besoin de garder une trace de vos propres cibles/actions. La fonctionnalité est déjà là, tout ce que vous avez à faire est d'appeler le code ci-dessous dans votre sous-classe pour déclencher l'événement:

[self sendActionsForControlEvents:UIControlEventValueChanged];

Ensuite, dans le contrôleur de vue ou la vue qui instancie votre coutume UIControl, il suffit de faire

[customControl addTarget:self action:@selector(whatever) forControlEvents:UIControlEventValueChanged];

pour événement personnalisé, il suffit de définir votre propre ENUM (par exemple, UIControlEventValueChanged est égal à 1 << 12). Assurez-vous simplement qu'il se trouve dans la plage autorisée définie par UIControlEventApplicationReserved

+0

C'était ce dont j'avais besoin, merci –