Mantenere selezionato un pulsante UIB dopo un tocco


90

Dopo che il mio utente fa clic su un pulsante, desidero che il pulsante rimanga premuto per tutto il tempo in cui eseguo un'operazione di rete. Quando l'operazione di rete è completa, voglio che il pulsante torni allo stato predefinito.

Ho provato a chiamare - [UIButton setSelected:YES]subito dopo aver premuto il pulsante (con una chiamata corrispondente a - al [UIButton setSelected:NO]termine dell'operazione di rete) ma sembra che non faccia nulla. Stessa cosa se chiamo setHighlighted:.

Suppongo di poter provare a scambiare l'immagine di sfondo per indicare uno stato selezionato per la durata dell'operazione di rete, ma sembra un trucco. Qualche suggerimento migliore?

Ecco come appare il mio codice:

- (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;
}

Risposte:


73

Come stai impostando le immagini per i diversi UIControlStatessul pulsante? Stai impostando un'immagine di sfondo per UIControlStateHighlightedcosì come UIControlStateSelected?

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

Se stai impostando lo stato selezionato sull'evento touch down del pulsante anziché ritoccare all'interno, il tuo pulsante sarà effettivamente in uno stato evidenziato + selezionato, quindi ti consigliamo di impostare anche quello.

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

Modificare:

Per riassumere le mie osservazioni nei commenti e per indirizzare il codice che hai pubblicato ... devi impostare le tue immagini di sfondo per lo UIControlstato completo in cui ti trovi. Secondo il tuo frammento di codice, questo stato di controllo sarebbe disabilitato + selezionato + evidenziato per la durata del funzionamento della rete. Ciò significa che dovresti fare questo:

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

Se rimuovi il highlighted = YES, allora avrai bisogno di questo:

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

Prendi la foto?


In effetti, credo di fare quello che suggerisci; Lo sto solo facendo tramite Interface Builder. Ho aggiunto il codice che sto usando alla mia domanda sopra ... forse questo farebbe luce sul problema? Il comportamento che desidero è che il pulsante rimanga selezionato per tutta la durata dell'operazione di rete. Quello che vedo è che il pulsante si evidenzia quando viene toccato, quindi l'evidenziazione scompare quando il tocco è terminato. Il pulsante -non viene mai selezionato. Perché questo non funzionerebbe non ha senso per me, quindi mi sento come se stessi facendo qualcosa di stupido. Ho controllato tutte le mie connessioni IB e sono buone ...
Greg Maletic,

Non credo che tu possa impostare un'immagine di sfondo per lo stato evidenziato + selezionato in Interface Builder, solo gli stati evidenziati e selezionati separatamente. Se il tuo pulsante era in uno stato tale che evidenziato e selezionato fossero entrambi impostati, credo che verrà impostato come predefinito sulla tua immagine normale, non su nessuna delle immagini evidenziate o selezionate. Dal tuo codice, stai impostando lo stato del pulsante in modo tale che sia selezionato che evidenziato siano SÌ. CheckInButtonPushed è collegato a "Touch Up Inside" o qualcos'altro?
Bryan Henry,

Sì, è collegato a "Touch Up Inside". E se rimuovo il codice relativo allo stato "evidenziato", continua a non funzionare. Lo stato "selezionato" non viene mai mostrato.
Greg Maletic,

Inoltre, perché disabiliti il ​​pulsante? Ciò significherebbe effettivamente che lo stato del pulsante è disabilitato + evidenziato + selezionato. Se hai rimosso l'impostazione della linea evidenziata su YES, hai disabilitato + selezionato, quindi devi impostare un'immagine per lo stato (UIControlStateDisabled | UIControlStateSelected).
Bryan Henry,

Ok, questo era il problema. Quando ho rimosso la funzionalità di disabilitazione, ha funzionato come previsto. Grazie! (Per rispondere alla tua domanda, disabilito il pulsante perché non voglio che nessuno lo
prema di

30

Ho un modo più semplice. Basta usare "performSelector" con 0 ritardo per eseguire [button setHighlighted:YES]. Ciò eseguirà la ri-evidenziazione al termine del ciclo di esecuzione corrente.

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

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

28

"Tutto migliora all'accensione"

    button.selected = !button.selected;

funziona perfettamente ... dopo aver collegato la presa al pulsante in Interface Builder.

Non è necessario impostareBackgroundImage: forState :, il builder consente di specificare le immagini di sfondo (viene ridimensionato se necessario) o / e in primo piano (non ridimensionato).


27

Prova a utilizzare NSOperationQueue per ottenere ciò. Prova il codice come segue:

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

Spero che questo ti aiuti.


Questa è un'ottima soluzione, Roberto e Parth. Un piccolo dettaglio, tuttavia, è che occasionalmente vedrai uno "sfarfallio" se l'utente tiene il dito premuto sul pulsante. C'è un modo per prevenire lo sfarfallio?
Scott Lieberman

8

Usa un blocco in modo da non dover creare un metodo completamente separato:

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

Aggiornare

Per essere chiari è ancora necessario impostare lo sfondo (o l'immagine normale) per gli stati della combinazione così come quelli normali come sbrocket dice nella risposta accettata. Ad un certo punto il tuo pulsante sarà sia selezionato che evidenziato e non avrai un'immagine per quello a meno che tu non faccia qualcosa del genere:

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

In caso contrario, il pulsante può tornare all'immagine UIControlStateNormal per il breve stato selezionato + evidenziato e vedrai un lampo.


Cordiali saluti dispatch_get_current_queue()è dichiarato come "inaffidabile".
Jacob Relkin

1
Dov'è detto? Qual è l'alternativa?
Bob Spryn

C'è un significato nell'uso dispatch_afterrispetto a dispatch_async?
Ilya

Sì. dispatch_asyncè una scelta migliore.
Bob Spryn

4

In fretta lo sto facendo come segue.

Creo una sottoclasse UIButtone implemento una proprietà personalizzatastate

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
        }
    }

}

Funziona perfettamente per me.


1

Ho avuto un problema simile in cui volevo che un pulsante mantenga l'evidenziazione dopo il clic. Il problema è che se provi a utilizzare l' setHighlighted:YESazione di clic all'interno dell'azione, verrà ripristinata subito dopo aver fatto clic sull'azione,- (IBAction)checkInButtonPushed

Ho risolto questo problema utilizzando un NSTimer come questo

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

e poi chiama setHighlighted:YESdal mio selectCurrentIndexmetodo. Uso i UIButtonTypeRoundedRectpulsanti normali .


0

Ho un altro modo ... se non vuoi usare le immagini e vuoi l'effetto di un pulsante premuto, puoi sottoclassare il pulsante ed ecco il mio codice:

nel file .h:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

Nel file .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

Ecco un'implementazione C # / MonoTouch (Xamarin.iOS) che utilizza gli approcci presentati sopra. Presume che abbiate già impostato lo stato dell'immagine evidenziato e configura gli stati selezionati e selezionati in modo che utilizzino la stessa immagine.

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;
        });
    });
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.