Come fermare l'animazione UIButton indesiderata al cambio di titolo?


211

In iOS 7 i miei titoli UIButton si animano dentro e fuori nel momento sbagliato, in ritardo. Questo problema non appare su iOS 6. Sto solo usando:

[self setTitle:text forState:UIControlStateNormal];

Preferirei che ciò accada all'istante e senza cornice vuota. Questo battito di ciglia è particolarmente fonte di distrazione e distoglie l'attenzione dalle altre animazioni.


Stiamo vivendo anche questo. Non sono sicuro se si tratta di un bug iOS7 o qualcosa che dovremmo correggere.
Ondeggia il

Prova, [self.button setHighlighted: NO];
karthika,

Grazie per queste idee Ho provato setHighlighted: NO, ma senza fortuna lì. Sono in grado di ridurre il lampeggiamento inserendo setTitle all'interno: [UIView animateWithDuration: animazioni 0.0f: ^ {...}];
exsulto,

1
È possibile utilizzare questa soluzione, in alcuni casi: self.button.titleLabel.text = text. Ma questo non ridimensiona la cornice dell'etichetta e non funziona correttamente con UIControlStates
zxcat

Questa è una soluzione intelligente. Giocherò con questo e vedrò cosa succede, purtroppo sto usando UIControlStates.
exsulto,

Risposte:


165

Funziona con pulsanti personalizzati:

[UIView setAnimationsEnabled:NO];
[_button setTitle:@"title" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Per i pulsanti di sistema è necessario aggiungerlo prima di riattivare le animazioni (grazie @Klaas):

[_button layoutIfNeeded];

12
Sfortunatamente questo non sembra funzionare. Né si esibisce senza Animation
Sway

9
Ok, quindi la soluzione che ha funzionato alla fine è stata quella di lasciare vuoto il testo originale di UIButton in modo che quando lo imposto con il codice non attivi l'animazione.
Ondeggia il

27
Funziona solo se imposti il ​​tipo di pulsante su personalizzato, secondo questa risposta stackoverflow.com/a/20718467/62 .
Liron Yahdav,

15
A partire da iOS 7.1 ho dovuto aggiungere[_button layoutIfNeeded];
Klaas

6
@LironYahdav se il tipo di pulsante è impostato su UIButtonTypeCustom, questa risposta non è richiesta.
DonnaLea,

262

Utilizzare il performWithoutAnimation:metodo e quindi imporre che il layout si verifichi immediatamente anziché successivamente.

[UIView performWithoutAnimation:^{
  [self.myButton setTitle:text forState:UIControlStateNormal];
  [self.myButton layoutIfNeeded];
}];

11
Funziona così come la risposta accettata, ma sembra più piacevole perché è più incapsulato: è impossibile dimenticare di aggiungere [UIView setAnimationsEnabled: YES] o rimuoverlo lungo la traccia.
siburb

19
Funziona con i pulsanti di sistema se si chiama [button layoutIfNeeded];all'interno del blocco.
Alexandre Blin

1
A proposito, per i pulsanti di sistema, layoutIfNeed dovrebbe essere chiamato dopo la modifica del testo
Yon

Questa è la soluzione migliore! Saluti
sachadso

Questo è corretto per me. È più votato e al 6 ° posto. Bello ...
Solgar

79

Cambia il tipo di pulsante in builder interfaccia modulo personalizzato.

inserisci qui la descrizione dell'immagine

Questo ha funzionato per me.


6
Soluzione migliore! Grazie.
Thomás Calmon,

3
Ma questo disabilita anche l'animazione sul pulsante clic. Voglio disabilitare solo l'animazione quando si mostra il pulsante.
Piotr Wasilewicz,

Funziona se non ti interessa l'animazione quando si tocca il pulsante.
Joaquin Pereira,

Ho impostato un paio di pulsanti in questo modo e ovviamente questa è la risposta più elegante per il mio caso. Bene grazie!
Zoltán,

79

In Swift puoi usare:

UIView.performWithoutAnimation {
    self.someButtonButton.setTitle(newTitle, forState: .normal)
    self.someButtonButton.layoutIfNeeded()
}

1
Questo era di gran lunga il metodo più semplice. E grazie per l'inclusione di una risposta rapida btw
simplexity

1
La migliore risposta per Swift!
Nubaslon,

Aveva un fastidioso bug in cui la modifica di un titolo UIButton mentre fuori schermo avrebbe causato strani tempi di animazione con interactivePopGestureRecognizer e questo l'aveva risolto. Penso comunque che sia un bug con il sistema operativo
SparkyRobinson il

Strano che .layoutIfNeeded () debba essere chiamato, ma l'ho provato in entrambi i modi in Swift 5 e sicuramente si anima ancora senza di esso.
wildcat12,

2
Non proprio. Se non chiami, layoutIfNeeded()il pulsante viene contrassegnato come necessario per essere ridisegnato, ma ciò non accadrà fino al passaggio del layout successivo, che sarà fuori dalperformWithoutAnimation
Paulw11

60

Notare che :

quando " buttonType " di _button è "UIButtonTypeSystem" , il codice sotto non è valido

[UIView setAnimationsEnabled:NO];
[_button setTitle:@"title" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

quando " buttonType " di _button è "UIButtonTypeCustom" , il codice sopra è valido .


Non riesco a credere quanto tempo ho trascorso prima di capire che devi solo cambiare il tipo di pulsante ... ugh ...
Sandy Chapman,

Funziona senza alcun codice. Cambia solo il tipo di pulsanti e funzionerà.
Alex Motor,

52

A partire da iOS 7.1 l'unica soluzione che ha funzionato per me è stata l'inizializzazione del pulsante con il tipo UIButtonTypeCustom.


Questo è l'approccio più sensato per chiunque non necessiti di UIButtonTypeSystem.
DonnaLea,

Questo ha funzionato meglio per me, ho appena creato un pulsante CUSTOM e l'ho fatto apparire ed evidenziare come un pulsante di sistema. Riesco a malapena a vedere la differenza ma non hai questo ritardo.
Travis M.

18

quindi trovo una soluzione funzionante:

_logoutButton.titleLabel.text = NSLocalizedString(@"Logout",);
[_logoutButton setTitle:_logoutButton.titleLabel.text forState:UIControlStateNormal];

per prima cosa cambiamo titolo per il pulsante, quindi ridimensioniamo il pulsante per questo titolo


1
Uso la stessa soluzione alternativa. La risposta accettata non funziona per me.
deej

Questo fa lampeggiare il titolo due volte, almeno con iOS 8.
Jordan H

1
Questo funziona per me in 7.1 e 8.1 senza lampeggiare. Semplice ed efficace
Todd,

Funziona perfettamente su iOS 11, anche se ho dovuto utilizzare di nuovo la stessa stringa per la seconda riga (l'utilizzo del titolo dell'etichetta del pulsante ha causato il lampeggiamento).
SilverWolf - Ripristina Monica il

13

Imposta il tipo di pulsante su UIButtonTypeCustom e smetterà di lampeggiare


Come possono tutte quelle soluzioni "alternative" avere così tanti voti positivi quando questa semplice risposta deve risolvere questo problema il 99% delle volte ...
Rob

12

Swift 5

myButton.titleLabel?.text = "title"
myButton.setTitle("title", for: .normal)

Non ho idea del perché funzioni, ma funziona ed è la soluzione più pulita. UIKit è strano.
Nathan Hosselton,

11

Ho fatto un'estensione Swift per fare questo:

extension UIButton {
    func setTitleWithoutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, forState: .Normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

Funziona per me su iOS 8 e 9, con UIButtonTypeSystem.

(Il codice è per Swift 2, Swift 3 e Objective-C dovrebbero essere simili)


Non lo useremo ora ma è molto utile avere in giro!
Francis Reynolds,

9

Imposta il tipo di UIButton come personalizzato. Ciò dovrebbe rimuovere le animazioni di dissolvenza in entrata e in uscita.


1
Questo dovrebbe avere più voti! Funziona perfettamente e disabilita l'animazione alla causa principale, anziché queste altre soluzioni alternative.
Jesper Schläger,

7

Di solito, semplicemente impostando il tipo di pulsante su Personalizzato funziona per me, ma per altri motivi ho dovuto sottoclassare UIButton e riportare il tipo di pulsante sul valore predefinito (Sistema), quindi il lampeggiamento riappariva.

L'impostazione UIView.setAnimationsEnabled(false)prima di cambiare il titolo e poi di nuovo vero dopo non ha evitato il battito di ciglia, non importa se ho chiamato self.layoutIfNeeded()o meno.

Questo, e solo questo nel seguente esatto ordine, ha funzionato per me con iOS 9 e 10 beta:

1) Crea una sottoclasse per UIButton (non dimenticare di impostare anche la classe personalizzata per il pulsante nello Storyboard).

2) Sostituisci setTitle:forState:come segue:

override func setTitle(title: String?, forState state: UIControlState) {

    UIView.performWithoutAnimation({

        super.setTitle(title, forState: state)

        self.layoutIfNeeded()
    })
}

In Interface Builder, è possibile lasciare il tipo di pulsante su Sistema, non è necessario modificarlo in Tipo personalizzato affinché questo approccio funzioni.

Spero che questo aiuti qualcun altro, ho lottato per così tanto tempo con i fastidiosi pulsanti lampeggianti che spero di evitarlo ad altri;)


Non dimenticare layoutIfNeeded():]
Tai Le

6

Puoi semplicemente creare un pulsante personalizzato e smetterà di animarsi mentre cambi il titolo.

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [btn setTitle:@"the title" forState:UIControlStateNormal];

puoi anche farlo nella casella di controllo Storyboard: seleziona il pulsante nello storyboard -> seleziona la finestra di ispezione degli attributi (quarto da sinistra) -> nel menu a discesa "Tipo", seleziona "Personalizzato" invece di "Sistema" che probabilmente è stato selezionato .

In bocca al lupo!


3

Puoi rimuovere le animazioni dal livello dell'etichetta del titolo:

    [[[theButton titleLabel] layer] removeAllAnimations];

Ho esaminato tutte le risposte. Questo è il migliore.
Rudolf Adamkovič,

2
Lampeggia ancora ma è meglio.
Lucien,

QUESTA DOVREBBE ESSERE LA RISPOSTA.
MXC

3

Swift 4 versione di Xhacker Liu risposta

import Foundation
import UIKit
extension UIButton {
    func setTitleWithOutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
} 

1

UIButton con systemtype ha un'animazione implicita attivata setTitle(_:for:). Puoi risolverlo in due modi diversi:

  1. Impostare il tipo di pulsante su custom, dal codice o Interface Builder:
let button = UIButton(type: .custom)

inserisci qui la descrizione dell'immagine

  1. Disabilita l'animazione dal codice:
UIView.performWithoutAnimation {
    button.setTitle(title, for: .normal)
    button.layoutIfNeeded()
}

0

Ho scoperto che questa soluzione alternativa funziona anche con UIButtonTypeSystem ma funzionerà solo se il pulsante è abilitato per qualche motivo.

[UIView setAnimationsEnabled:NO];
[_button setTitle:@"title" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Quindi dovrai aggiungerli se è necessario disabilitare il pulsante quando si imposta il titolo.

[UIView setAnimationsEnabled:NO];
_button.enabled = YES;
[_button setTitle:@"title" forState:UIControlStateNormal];
_button.enabled = NO;
[UIView setAnimationsEnabled:YES];

(iOS 7, Xcode 5)


Ho appena confermato che questa soluzione alternativa non funziona più su iOS 7.1.
sCha

non pensi di aver trovato una soluzione per 7.1?
George Green,

@GeorgeGreen non è riuscito a trovare alcuna soluzione funzionante per UIButtonTypeSystem . Ho dovuto usare UIButtonTypeCustom .
sCha

Da 7.1, dovrai applicare le modifiche al titolo a tutti gli stati, impostandolo solo per lo stato normale non si applica più. [_button setTitle:@"title" forState:UIControlStateDisabled]
Sam,

0

La combinazione di grandi risposte sopra porta alla seguente soluzione alternativa per UIButtonTypeSystem :

if (_button.enabled)
{
    [UIView setAnimationsEnabled:NO];
    [_button setTitle:@"title" forState:UIControlStateNormal];
    [UIView setAnimationsEnabled:YES];
}
else // disabled
{
    [UIView setAnimationsEnabled:NO];
    _button.enabled = YES;
    [_button setTitle:@"title" forState:UIControlStateNormal];
    _button.enabled = NO;
    [UIView setAnimationsEnabled:YES];
}

0

Ho avuto il brutto problema di animazione durante la modifica dei titoli dei pulsanti nei controller di visualizzazione all'interno di un UITabBarController. I titoli che erano stati originariamente ambientati nello storyboard apparvero per un po 'prima di svanire nei loro nuovi valori.

Volevo scorrere tutte le visualizzazioni secondarie e usare i titoli dei pulsanti come chiavi per ottenere i loro valori localizzati con NSLocalizedString, come;

for(UIView *v in view.subviews) {

    if ([v isKindOfClass:[UIButton class]]) {
        UIButton *btn = (UIButton*)v;
        NSString *newTitle = NSLocalizedString(btn.titleLabel.text, nil);
        [btn setTitle:newTitle];
    }

}

Ho scoperto che ciò che attiva l'animazione è davvero la chiamata a btn.titleLabel.text. Quindi, per fare ancora uso degli storyboard e avere i componenti dinamicamente localizzati in questo modo, mi assicuro di impostare l'ID di restauro di ogni pulsante (in Identity Inspector) sullo stesso titolo e di usarlo come chiave invece del titolo;

for(UIView *v in view.subviews) {

    if ([v isKindOfClass:[UIButton class]]) {
        UIButton *btn = (UIButton*)v;
        NSString *newTitle = NSLocalizedString(btn.restorationIdentifier, nil);
        [btn setTitle:newTitle];
    }

}

Non ideale, ma funziona ..


0

Puoi effettivamente impostare il titolo al di fuori di un blocco di animazione, assicurati di chiamare layoutIfNeeded()all'interno di un performWithoutAnimation:

button1.setTitle("abc", forState: .Normal)
button2.setTitle("abc", forState: .Normal)
button3.setTitle("abc", forState: .Normal)
UIView.performWithoutAnimation {
    self.button1.layoutIfNeeded()
    self.button2.layoutIfNeeded()
    self.button3.layoutIfNeeded()
}

Se hai un sacco di pulsanti, considera di chiamare semplicemente layoutIfNeeded()la super vista:

button1.setTitle("abc", forState: .Normal)
button2.setTitle("abc", forState: .Normal)
button3.setTitle("abc", forState: .Normal)
UIView.performWithoutAnimation {
    self.view.layoutIfNeeded()
}

0

L'estensione Xhacker Liu convertita in Swift 3:

extension UIButton {
    func setTitleWithoutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

-1

Forse generare 2 animazioni e 2 pulsanti è una soluzione migliore, per evitare il problema che si presenta con l'animazione e la modifica del testo di un pulsante?

Ho creato un secondo uibutton e generato 2 animazioni, questa soluzione funziona senza problemi.

    _button2.hidden = TRUE;
    _button1.hidden = FALSE;

    CGPoint startLocation = CGPointMake(_button1.center.x, button1.center.y - 70);
    CGPoint stopLocation  = CGPointMake(_button2.center.x, button2.center.y- 70);


    [UIView animateWithDuration:0.3 animations:^{ _button2.center = stopLocation;} completion:^(BOOL finished){_button2.center = stopLocation;}];
    [UIView animateWithDuration:0.3 animations:^{ _button1.center = startLocation;} completion:^(BOOL finished){_button1.center = startLocation;}];

-1

Ho capito che funziona con una combinazione di risposte:

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^{

        [button setTitle:@"Title" forState:UIControlStateNormal];

    }];

-1

Una comoda estensione per la modifica del titolo dei pulsanti animati in Swift che si adatta perfettamente all'implementazione predefinita:

import UIKit

extension UIButton {
  /// By default iOS animated the title change, which is not desirable in reusable views
  func setTitle(_ title: String?, for controlState: UIControlState, animated: Bool = true) {
    if animated {
      setTitle(title, for: controlState)
    } else {
      UIView.setAnimationsEnabled(false)
      setTitle(title, for: controlState)
      layoutIfNeeded()
      UIView.setAnimationsEnabled(true)
    }
  }
}

@Fogmeister 1. La mia risposta è diversa 2. Sintassi Swift aggiornata 3. Coerente con l'API di Apple per UIButton.
Richard Topchii,
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.