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.