66 votes

Le registre UISegmentedControl tape sur le segment sélectionné

J'ai un contrôle segmenté où l'utilisateur peut choisir comment ordonner une liste. Cela fonctionne bien.

Cependant, j'aimerais que lorsqu'on touche un segment déjà sélectionné, l'ordre soit inversé. J'ai tout le code en place, mais je ne sais pas comment enregistrer les tapotements sur ces segments. Il semble que le seul événement de contrôle que vous pouvez utiliser soit UIControlEventValueChanged, mais cela ne fonctionne pas (puisque le segment sélectionné ne change pas réellement).

Existe-t-il une solution à ce problème ? Et si oui, quelle est-elle ?

Merci d'avance !

51voto

Julian Points 801

Vous pouvez sous-classer UISegmentedControl et ensuite override setSelectedSegmentIndex:

- (void) setSelectedSegmentIndex:(NSInteger)toValue {
    if (self.selectedSegmentIndex == toValue) {
        [super setSelectedSegmentIndex:UISegmentedControlNoSegment];
    } else {
        [super setSelectedSegmentIndex:toValue];        
    }
}

Si vous utilisez l'IB, assurez-vous de définir la classe de votre UISegmentedControl à votre sous-classe.

Maintenant, vous pouvez écouter le même UIControlEventValueChanged comme vous le feriez normalement, sauf que si l'utilisateur a désélectionné le segment, vous verrez apparaître un selectedSegmentIndex égal à UISegmentedControlNoSegment :

-(IBAction) valueChanged: (id) sender {
    UISegmentedControl *segmentedControl = (UISegmentedControl*) sender;
    switch ([segmentedControl selectedSegmentIndex]) {
        case 0:
            // do something
            break;
        case 1:
            // do something
            break;
        case UISegmentedControlNoSegment:
            // do something
            break;
        default:
            NSLog(@"No option for: %d", [segmentedControl selectedSegmentIndex]);
    }
}

0 votes

Pour iOS5.1, cela fonctionne parfaitement avec la solution de Bob De Graaf.

32voto

davidav Points 475

Je pense que c'est même un peu mieux si vous utilisez -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ---car c'est le comportement de UISegmentedControl. En outre, il semble que vous n'ayez pas besoin de surcharger la fonction -(void)setSelectedSegmentIndex:(NSInteger)toValue

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    
    NSInteger current = self.selectedSegmentIndex;
    [super touchesBegan:touches withEvent:event];
    if (current == self.selectedSegmentIndex) 
        [self sendActionsForControlEvents:UIControlEventValueChanged];
}

1 votes

Vous pourriez ajouter [self setSelectedSegmentIndex:UISegmentedControlNoSegment]; au début de la if (qui devrait vraiment utiliser des accolades, IMHO)

3 votes

Voir cette réponse pour une version mise à jour d'iOS 7 : stackoverflow.com/a/17652998/292145

20voto

Henrik N Points 4447

Je le voulais moi-même. J'ai pris la solution de Julian (merci !) et l'ai légèrement modifiée.

La sous-classe UISegmentedControl suivante déclenche simplement la fonction UIControlEventValueChanged même si la valeur n'a pas changé, ce qui est évidemment un peu bizarre, mais fonctionne bien dans mon cas et permet de garder les choses simples.

AKSegmentedControl.h

#import <UIKit/UIKit.h>

@interface AKSegmentedControl : UISegmentedControl {
}

@end

AKSegmentedControl.m

#import "AKSegmentedControl.h"

@implementation AKSegmentedControl

- (void)setSelectedSegmentIndex:(NSInteger)toValue {
  // Trigger UIControlEventValueChanged even when re-tapping the selected segment.
  if (toValue==self.selectedSegmentIndex) {
    [self sendActionsForControlEvents:UIControlEventValueChanged];
  }
  [super setSelectedSegmentIndex:toValue];        
}

@end

0 votes

Cela semble être l'astuce que je cherchais - j'ai un contrôle segmenté avec un segment dont j'ai besoin pour déclencher une vue modale qui s'affiche lorsqu'il est touché. Merci.

0 votes

Pour un contrôle unique segmenté (comme Petert l'a mentionné), voir aussi gist.github.com/401670 .

2 votes

Cela ne fonctionne pas pour moi dans iOS 6.1. Cette méthode est appelée une fois, mais lorsqu'elle répond aux touches, elle n'est pas appelée. On dirait qu'Apple contourne ses propres setters et getters.

12voto

EricS Points 5072

Cela fonctionne à la fois sur iOS 4 et 5 :

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  int oldValue = self.selectedSegmentIndex;
  [super touchesBegan:touches withEvent:event];
  if ( oldValue == self.selectedSegmentIndex )
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

0 votes

Comment cela fonctionne-t-il ? Pourquoi appelez-vous [super touchesBegan:touches withEvent:event] ? Que se passe-t-il dans la super version ?

1 votes

Il envoie un message UIControlEventValueChanged lorsque le segment actif a été touché. L'appel de [super touchesBegan:touches withEvent:event] exécute le code normal de traitement des événements fourni par le système - il modifiera la valeur si l'utilisateur touche un segment non actif et enverra lui-même cet événement dans ce cas.

0 votes

J'aime ça. Mais pour que la sélection devienne réellement désélectionnée, dans la partie principale de mon code (pas dans la sous-classe ici), c'est là que je l'ai définie comme désélectionnée, à l'intérieur de l'IBAction Change : - (IBAction)addSSslotSelectorChange:(id)sender { if(slotSelector.selectedSegmentIndex == [scratch_format.slot intValue]) { slotSelector.selectedSegmentIndex = -1; } scratch_format.slot = [NSNumber numberWithInt:slotSelector.selectedSegmentIndex]; NSLog(@"Slot changed to: %i",slotSelector.selectedSegmentIndex); }

11voto

Bob de Graaf Points 1054

La solution actuelle présentée ne fonctionne toujours pas, car setSelectedSegmentIndex n'est jamais appelé à moins qu'un nouveau segment ne soit réellement touché. Au moins dans mon cas, cela n'a jamais fonctionné, j'utilise iOS5 cependant, peut-être que cette solution a fonctionné dans iOS4. Quoi qu'il en soit, voici ma solution. Elle nécessite une méthode de sous-classe supplémentaire, qui est la suivante :

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{    
    [self setSelectedSegmentIndex:self.selectedSegmentIndex];
    [super touchesEnded:touches withEvent:event];
}

Bonne chance !

1 votes

Merci. Cette méthode fonctionne dans iOS 5, alors que l'autre méthode fonctionnait dans iOS 3 et 4.

0 votes

Pour que cela fonctionne sous iOS 5, vous devez ajouter [self sendActionsForControlEvents:UIControlEventValueChanged] ;

0 votes

Pour moi toucheBegan a fonctionné. Ce qui ne produit pas entièrement le comportement de la bascule, mais je l'ai personnalisé dans mon code. Merci

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