web-dev-qa-db-fra.com

Garder un bouton UIB sélectionné après un toucher

Une fois que mon utilisateur a cliqué sur un bouton, je souhaite que ce bouton reste enfoncé pendant que j'effectue une opération sur le réseau. Une fois l'opération réseau terminée, je souhaite que le bouton revienne à son état par défaut.

J'ai essayé d'appeler -[UIButton setSelected:YES] juste après le bouton Push (avec un appel correspondant à -[UIButton setSelected:NO] après la fin de l'opération réseau), mais il ne semble rien y faire. Même chose si j'appelle setHighlighted:.

Je suppose que je pourrais essayer d’échanger l’image d’arrière-plan pour indiquer un état sélectionné pendant la durée de l’opération réseau, mais cela semble être un hack. De meilleures suggestions?

Voici à quoi ressemble mon code:

- (IBAction)checkInButtonPushed
{
    self.checkInButton.enabled = NO;
    self.checkInButton.selected = YES;
    self.checkInButton.highlighted = YES;
    [self.checkInActivityIndicatorView startAnimating];
    [CheckInOperation startWithPlace:self.place delegate:self];
}

- (void)checkInCompletedWithNewFeedItem:(FeedItem*)newFeedItem wasNewPlace:(BOOL)newPlace possibleError:(NSError*)error;
{
    [self.checkInActivityIndicatorView stopAnimating];
    self.checkInButton.enabled = YES;
    self.checkInButton.selected = NO;
    self.checkInButton.highlighted = NO;
}
88
Greg Maletic

Comment définissez-vous les images pour les différentes UIControlStates sur le bouton? Définissez-vous une image de fond pour UIControlStateHighlighted ainsi que UIControlStateSelected?

UIImage *someImage = [UIImage imageNamed:@"SomeResource.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
[button setBackgroundImage:someImage forState:UIControlStateSelected];

Si vous définissez l'état sélectionné sur l'événement de toucher du bouton plutôt que de le retoucher à l'intérieur, votre bouton sera réellement dans un état en surbrillance + sélectionné, vous devrez donc également le définir.

[button setBackgroundImage:someImage forState:(UIControlStateHighlighted|UIControlStateSelected)];

Modifier:

Pour résumer mes remarques dans les commentaires et pour adresser le code que vous avez posté ... vous devez définir vos images de fond pour l'état UIControl complet dans lequel vous vous trouvez. Selon votre extrait de code, cet état de contrôle serait désactivé + sélectionné + mis en évidence pour la durée de l'opération du réseau. Cela signifie que vous devez faire ceci:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateHighlighted|UIControlStateSelected)];

Si vous supprimez le highlighted = YES, vous en aurez besoin:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateSelected)];

Obtenez la photo?

73
Bryan Henry

J'ai un moyen plus facile. Utilisez simplement "performSelector" avec un délai de 0 pour exécuter [button setHighlighted:YES]. Ceci effectuera une nouvelle surbrillance après la fin du cycle courant.

- (IBAction)buttonSelected:(UIButton*)sender {
    NSLog(@"selected %@",sender.titleLabel.text);
    [self performSelector:@selector(doHighlight:) withObject:sender afterDelay:0];
}

- (void)doHighlight:(UIButton*)b {
    [b setHighlighted:YES];
}
29
Hlung

Essayez d’utiliser NSOperationQueue pour cela. Essayez le code comme suit:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    theButton.highlighted = YES;
}];

J'espère que cela t'aides.

27
roberto.buratti

"Tout va mieux quand on allume"

    button.selected = !button.selected;

fonctionne parfaitement ... après avoir connecté la prise au bouton dans Interface Builder.

Vous n'avez pas besoin de définirBackgroundImage: forState :, le générateur vous permet de spécifier les images d'arrière-plan (redimensionné si nécessaire) ou/et de premier plan (pas de redimensionnement).

27

Utilisez un bloc pour ne pas avoir à construire une méthode complètement séparée:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
    theButton.highlighted = YES;
});

Mettre à jour

Pour être clair, vous devez toujours définir l’arrière-plan (ou une image normale) pour les états de combinaison ainsi que pour ceux qui sont normaux, comme le dit sbrocket dans la réponse acceptée. À un moment donné, votre bouton sera à la fois sélectionné et mis en surbrillance et vous n'aurez une image pour cela que si vous faites quelque chose comme ceci:

[button setBackgroundImage:someImage forState (UIControlStateHighlighted|UIControlStateSelected)];

Sinon, votre bouton peut revenir à l'image UIControlStateNormal pour l'état bref sélectionné + mis en surbrillance et vous verrez un clignotement.

8
Bob Spryn

Dans Swift, je le fais comme suit. 

Je crée une sous-classe de UIButton et implémente une propriété personnalisée state 

class ActiveButton: UIButton {

    private var _active = false
    var active:Bool {
        set{
            _active = newValue
            updateState()
        }
        get{
            return _active
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.addTarget(self, action: #selector(ActiveButton.touchUpInside(_:)), forControlEvents: .TouchUpInside)
    }

    func touchUpInside(sender:UIButton) {
        active = !active
    }

    private func updateState() {
        NSOperationQueue.mainQueue().addOperationWithBlock {
            self.highlighted = self.active
        }
    }

}

Fonctionne parfaitement pour moi. 

2
Eike

J'ai eu un problème similaire où je voulais qu'un bouton garde sa surbrillance après un clic . Le problème est que si vous essayez d'utiliser setHighlighted:YES à l'intérieur de votre action de clic, elle sera réinitialisée juste après que vous avez cliqué sur l'action, - (IBAction)checkInButtonPushed

J'ai résolu ceci en utilisant un NSTimer comme celui-ci

NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
                                         target: self
                                       selector: @selector(selectCurrentIndex)
                                       userInfo: nil
                                        repeats: NO];

puis appelez setHighlighted:YES à partir de ma méthode selectCurrentIndex. J'utilise des boutons UIButtonTypeRoundedRect réguliers.

1
fredrik

J'ai un autre moyen ... si vous ne voulez pas utiliser d'images et que vous voulez l'effet d'un bouton enfoncé, vous pouvez sous-classer le bouton et voici mon code:

dans le fichier .h:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

Dans le fichier .m: 

#import <QuartzCore/QuartzCore.h>


 @implementation reservasButton

 -(void)setupView {  //This is for Shadow

    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowOpacity = 0.5; 
    self.layer.shadowRadius = 1;    
    self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f); //comment
    //   self.layer.borderWidth = 1;
    self.contentVerticalAlignment   = UIControlContentVerticalAlignmentCenter;
    self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

    // [self setBackgroundColor:[UIColor whiteColor]];

    //  self.opaque = YES;


}

-(id)initWithFrame:(CGRect)frame{
    if((self = [super initWithFrame:frame])){
        [self setupView];
    }

    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    if((self = [super initWithCoder:aDecoder])){
        [self setupView];
    }

    return self;
}

//Here is the important code

 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{


  if (isPressed == FALSE) {

      self.contentEdgeInsets = UIEdgeInsetsMake(1.0,1.0,-1.0,-1.0);
      self.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
      self.layer.shadowOpacity = 0.8;

      [super touchesBegan:touches withEvent:event];

      isPressed = TRUE;

     }
     else {

         self.contentEdgeInsets = UIEdgeInsetsMake(0.0,0.0,0.0,0.0);
         self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
         self.layer.shadowOpacity = 0.5;

         [super touchesEnded:touches withEvent:event];

         isPressed = FALSE;

     }


 } `
0
Pach

Voici une implémentation C #/MonoTouch (Xamarin.iOS) utilisant les approches présentées ci-dessus. Cela suppose que vous avez déjà défini l'état de l'image surlignée et configure les états sélectionnés et | surlignés pour qu'ils utilisent la même image. 

var selected = button.BackgroundImageForState(UIControlState.Highlighted);
button.SetBackgroundImage(selected, UIControlState.Selected);
button.SetBackgroundImage(selected, UIControlState.Selected | UIControlState.Highlighted);
button.TouchUpInside += delegate
{
    NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(0), delegate
    {
        button.Highlighted = true;
        NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(200), delegate
        {
            button.Highlighted = false;
        });
    });
};
0
t9mike