Wie kann ich unerwünschte UIButton-Animationen bei Titeländerungen stoppen?

211

In iOS 7 werden meine UIButton-Titel zur falschen Zeit ein- und ausgeblendet - spät. Dieses Problem tritt unter iOS 6 nicht auf. Ich verwende nur:

[self setTitle:text forState:UIControlStateNormal];

Ich würde es vorziehen, wenn dies sofort und ohne leeren Rahmen geschieht. Dieses Blinken lenkt besonders ab und lenkt die Aufmerksamkeit von anderen Animationen ab.

exsulto
quelle
Wir erleben das auch. Ich bin mir nicht sicher, ob es sich um einen iOS7-Fehler handelt oder etwas, das wir beheben sollten.
Sway
Versuchen Sie, [self.button setHighlighted: NO];
Karthika
Danke für diese Ideen. Ich habe setHighlighted ausprobiert: NEIN, aber kein Glück. Ich kann das Blinken reduzieren, indem ich setTitle in: [UIView animateWithDuration: 0.0f animations: ^ {...}];
Exsulto
1
Sie können diese Problemumgehung in einigen Fällen verwenden : self.button.titleLabel.text = text. Aber dies ändert nicht die Größe des Etikettenrahmens und funktioniert nicht richtig mit UIControlStates
zxcat
Das ist eine clevere Problemumgehung. Ich werde damit spielen und sehen, was passiert, leider benutze ich UIControlStates.
Exsulto

Antworten:

165

Dies funktioniert für benutzerdefinierte Schaltflächen:

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

Für Systemschaltflächen müssen Sie dies hinzufügen, bevor Sie Animationen wieder aktivieren (danke @Klaas):

[_button layoutIfNeeded];
Jacob K.
quelle
12
Leider scheint das nicht zu funktionieren. Weder ohne Animation
Sway
9
Ok, das Update, das am Ende funktioniert hat, war, den ursprünglichen UIButton-Text leer zu lassen, damit die Animation nicht ausgelöst wird, wenn ich ihn mit Code einstelle.
Sway
27
Dies funktioniert nur, wenn Sie den Typ der Schaltfläche gemäß dieser Antwort auf " custom" setzen . Stackoverflow.com/a/20718467/62 .
Liron Yahdav
15
Ab iOS 7.1 musste ich hinzufügen[_button layoutIfNeeded];
Klaas
6
@LironYahdav Wenn Sie den Schaltflächentyp auf UIButtonTypeCustom eingestellt haben, ist diese Antwort nicht erforderlich.
DonnaLea
262

Verwenden Sie die performWithoutAnimation:Methode und erzwingen Sie dann, dass das Layout sofort statt später erfolgt.

[UIView performWithoutAnimation:^{
  [self.myButton setTitle:text forState:UIControlStateNormal];
  [self.myButton layoutIfNeeded];
}];
Schneemann
quelle
11
Dies funktioniert genauso gut wie die akzeptierte Antwort, scheint aber besser zu sein, da sie gekapselter ist - es ist unmöglich zu vergessen, das [UIView setAnimationsEnabled: YES] hinzuzufügen oder es später zu entfernen.
Geschwister
19
Es funktioniert für Systemtasten, wenn Sie [button layoutIfNeeded];innerhalb des Blocks aufrufen .
Alexandre Blin
1
BTW, für Systemtasten, sollte layoutIfNeed aufgerufen werden , nachdem Text geändert
Yon
Dies ist die beste Lösung! Cheers
Sachadso
Das ist richtig für mich. Es ist am meisten gewählt und auf dem 6. Platz. Schön ...
Solgar
79

Ändern Sie den Schaltflächentyp in den Builder für benutzerdefinierte Formularschnittstellen.

Geben Sie hier die Bildbeschreibung ein

Das hat bei mir funktioniert.

Christos Chadjikyriacou
quelle
6
Beste Lösung! Danke dir.
Thomás Calmon
3
Dies deaktiviert aber auch die Animation auf Klick-Schaltfläche. Ich möchte nur die Animation deaktivieren, wenn die Schaltfläche angezeigt wird.
Piotr Wasilewicz
Dies funktioniert, wenn Sie sich beim Tippen auf die Schaltfläche nicht um die Animation kümmern.
Joaquin Pereira
Ich habe ein paar Knöpfe wie diesen eingestellt und dies ist offensichtlich die eleganteste Antwort für meinen Fall. Nett, danke!
Zoltán
79

In Swift können Sie verwenden:

UIView.performWithoutAnimation {
    self.someButtonButton.setTitle(newTitle, forState: .normal)
    self.someButtonButton.layoutIfNeeded()
}
Paulw11
quelle
1
Dies war bei weitem die einfachste Methode. Und danke für die schnelle Antwort übrigens
Simplexität
1
Beste Antwort für Swift!
Nubaslon
Hatte einen nervigen Fehler, bei dem das Ändern eines UIButton-Titels außerhalb des Bildschirms zu seltsamen Animationszeiten mit interaktivem PopGestureRecognizer führte, und dies löste das Problem. Ich denke immer noch, dass es ein Fehler mit dem Betriebssystem ist
SparkyRobinson
Seltsam, dass .layoutIfNeeded () aufgerufen werden muss, aber ich habe es in Swift 5 in beide Richtungen getestet und es wird definitiv immer noch ohne es animiert.
wildcat12
2
Nicht wirklich. Wenn Sie nicht anrufen, layoutIfNeeded()wird die Schaltfläche als neu gezeichnet markiert, dies geschieht jedoch erst beim nächsten Layout-Durchgang, der sich außerhalb desperformWithoutAnimation
Paulw11
60

Bitte beachten Sie :

Wenn " buttonType " von _button "UIButtonTypeSystem" ist , ist der folgende Code ungültig :

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

Wenn " buttonType " von _button "UIButtonTypeCustom" ist , ist der obige Code gültig .

shede333
quelle
Ich kann nicht glauben, wie viel Zeit ich verbracht habe, bevor ich herausgefunden habe, dass Sie nur den Schaltflächentyp ändern müssen ... ugh ...
Sandy Chapman
Funktioniert ohne Code. Ändern Sie nur den Schaltflächentyp und es wird funktionieren.
Alex Motor
52

Ab iOS 7.1 war die einzige Lösung, die für mich funktionierte, die Initialisierung der Schaltfläche mit Typ UIButtonTypeCustom.

Norbert
quelle
Dies ist der sinnvollste Ansatz für alle, die kein UIButtonTypeSystem benötigen.
DonnaLea
Dies funktionierte am besten für mich. Ich habe gerade eine CUSTOM-Schaltfläche erstellt und sie wie eine Systemschaltfläche aussehen und hervorheben lassen. Ich kann den Unterschied kaum erkennen, aber Sie haben diese Verzögerung nicht.
Travis M.
18

Also finde ich eine funktionierende Lösung:

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

Zuerst ändern wir den Titel für die Schaltfläche und ändern dann die Größe der Schaltfläche für diesen Titel

dubenko
quelle
1
Ich verwende die gleiche Problemumgehung. Die akzeptierte Antwort funktioniert bei mir nicht.
DJ
Dies führt dazu, dass der Titel zweimal blinkt, zumindest unter iOS 8.
Jordan H
1
Dies funktioniert bei mir sowohl in 7.1 als auch in 8.1 ohne zu blinken. Einfach und effektiv.
Todd
Funktioniert perfekt in iOS 11, obwohl ich dieselbe Zeichenfolge für die zweite Zeile erneut verwenden musste (die Verwendung des Titels der Schaltflächenbeschriftung führte zum Blinken).
SilverWolf - Stellen Sie Monica am
13

Setzen Sie den Schaltflächentyp auf UIButtonTypeCustom und er hört auf zu blinken

arunjos007
quelle
Wie können all diese Problemumgehungslösungen so viele positive Stimmen haben, wenn diese einfache Antwort dieses Problem 99% der Zeit lösen muss ...
Rob
12

Swift 5

myButton.titleLabel?.text = "title"
myButton.setTitle("title", for: .normal)
Carter Randall
quelle
Keine Ahnung, warum das funktioniert, aber es funktioniert und es ist die sauberste Lösung. UIKit ist komisch.
Nathan Hosselton
11

Ich habe eine Swift-Erweiterung erstellt, um dies zu tun:

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

        setTitle(title, forState: .Normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

Funktioniert für mich unter iOS 8 und 9 mit UIButtonTypeSystem.

(Der Code für Swift 2, Swift 3 und Objective-C sollte ähnlich sein.)

Xhacker Liu
quelle
Ich werde es jetzt nicht benutzen, aber es ist sehr praktisch, es in der Nähe zu haben!
Francis Reynolds
9

Legen Sie den UIButton-Typ als Benutzerdefiniert fest. Das sollte Ein- und Ausblenden von Animationen entfernen.

Amit Tandel
quelle
1
Dies sollte mehr positive Stimmen haben! Funktioniert einwandfrei und deaktiviert die Animation an der Hauptursache anstelle dieser anderen Problemumgehungen.
Jesper Schläger
7

Normalerweise funktioniert es für mich, einfach den Schaltflächentyp auf Benutzerdefiniert zu setzen. Aus anderen Gründen musste ich UIButton unterordnen und den Schaltflächentyp auf den Standardwert (System) zurücksetzen, damit das Blinken wieder angezeigt wurde.

Das Einstellen UIView.setAnimationsEnabled(false)vor dem Ändern des Titels und danach wieder auf "Wahr" hat das Blinken für mich nicht vermieden, egal ob ich angerufen habe self.layoutIfNeeded()oder nicht.

Dies und nur dies in der folgenden genauen Reihenfolge funktionierte bei iOS 9 und 10 Beta:

1) Erstellen Sie eine Unterklasse für UIButton (vergessen Sie nicht, die benutzerdefinierte Klasse für die Schaltfläche auch im Storyboard festzulegen).

2) Überschreiben Sie setTitle:forState:wie folgt:

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

    UIView.performWithoutAnimation({

        super.setTitle(title, forState: state)

        self.layoutIfNeeded()
    })
}

In Interface Builder können Sie den Schaltflächentyp dem System überlassen, ohne ihn in Benutzerdefinierten Typ ändern zu müssen, damit dieser Ansatz funktioniert.

Ich hoffe das hilft jemand anderem, ich habe so lange mit den nervigen blinkenden Knöpfen gekämpft, dass ich hoffe, es anderen zu vermeiden;)

cdf1982
quelle
Vergessen Sie nicht layoutIfNeeded():]
Tai Le
6

Sie können einfach eine benutzerdefinierte Schaltfläche erstellen, die beim Ändern des Titels nicht mehr animiert wird.

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

Sie können dies auch im Kontrollkästchen "Storyboard" tun: Wählen Sie die Schaltfläche im Storyboard -> wählen Sie den Attributinspektor (vierter von links) -> wählen Sie im Dropdown-Menü "Typ" die Option "Benutzerdefiniert" anstelle von "System", das wahrscheinlich ausgewählt wurde .

Viel Glück!

Mendy
quelle
3

Sie können die Animationen aus der Ebene des Titeletiketts entfernen:

    [[[theButton titleLabel] layer] removeAllAnimations];
Jacksonh
quelle
Ich ging alle Antworten durch. Dieser ist der beste.
Rudolf Adamkovič
2
Es blinkt immer noch, aber es ist besser.
Lucien
Dies sollte die Antwort sein.
mxcl
3

Swift 4 Version von Xhacker Liu Antwort

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
} 
faraz khonsari
quelle
1

UIButton mit systemTyp hat implizite Animation aktiviert setTitle(_:for:). Sie können das Problem auf zwei verschiedene Arten beheben:

  1. Stellen Sie den Schaltflächentyp customentweder im Code oder im Interface Builder auf ein:
let button = UIButton(type: .custom)

Geben Sie hier die Bildbeschreibung ein

  1. Animation aus Code deaktivieren:
UIView.performWithoutAnimation {
    button.setTitle(title, for: .normal)
    button.layoutIfNeeded()
}
sgl0v
quelle
0

Ich habe festgestellt , dass diese Problemumgehung funktioniert mit UIButtonTypeSystem als gut , aber nur funktionieren , wenn die Taste aktiviert aus irgendeinem Grunde.

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

Sie müssen diese also hinzufügen, wenn die Schaltfläche beim Festlegen des Titels deaktiviert werden soll.

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

(iOS 7, Xcode 5)

sCha
quelle
Ich habe gerade bestätigt, dass diese Problemumgehung unter iOS 7.1 nicht mehr funktioniert.
sCha
Nehmen Sie nicht an, Sie haben eine Lösung für 7.1 gefunden?
George Green
@GeorgeGreen konnte keine funktionierenden Lösungen für UIButtonTypeSystem finden . Ich musste UIButtonTypeCustom verwenden .
sCha
Seit 7.1 müssen Sie Titeländerungen auf alle Status anwenden, wobei die Einstellung nur für den normalen Status nicht mehr gilt. [_button setTitle:@"title" forState:UIControlStateDisabled]
Sam
0

Die Kombination der oben genannten hervorragenden Antworten führt zu folgender Problemumgehung für 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];
}
AppsolutEinfach
quelle
0

Ich habe das hässliche Animationsproblem beim Ändern von Schaltflächentiteln in View-Controllern in einem UITabBarController. Die Titel, die ursprünglich im Storyboard festgelegt wurden, wurden für kurze Zeit angezeigt, bevor sie in ihre neuen Werte übergingen.

Ich wollte alle Unteransichten durchlaufen und die Schaltflächentitel als Schlüssel verwenden, um ihre lokalisierten Werte mit NSLocalizedString abzurufen, z.

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

}

Ich fand heraus, dass das, was die Animation auslöst, wirklich der Aufruf von btn.titleLabel.text ist. Um die Storyboards weiterhin zu nutzen und die Komponenten so dynamisch zu lokalisieren, stelle ich sicher, dass die Wiederherstellungs-ID jeder Schaltfläche (im Identitätsinspektor) mit dem Titel identisch ist und diese als Schlüssel anstelle des Titels verwendet wird.

for(UIView *v in view.subviews) {

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

}

Nicht ideal, funktioniert aber ..

Michael
quelle
0

Sie können den Titel tatsächlich außerhalb eines Animationsblocks layoutIfNeeded()festlegen. Rufen Sie nur innerhalb einer performWithoutAnimation auf:

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

Wenn Sie eine Reihe von Schaltflächen haben, rufen Sie einfach die Superansicht layoutIfNeeded()auf:

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

Die Xhacker Liu-Erweiterung wurde in Swift 3 konvertiert:

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}
Paweł
quelle
-1

Vielleicht ist das Generieren von 2 Animationen und 2 Schaltflächen eine bessere Lösung, um das Problem zu vermeiden, das beim Animieren und Ändern des Textes einer Schaltfläche auftritt?

Ich habe einen zweiten Uibutton erstellt und 2 Animationen generiert. Diese Lösung funktioniert ohne Probleme.

    _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;}];
Koda
quelle
-1

Ich habe es mit einer Kombination von Antworten zum Laufen gebracht:

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^{

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

    }];
Jaspis
quelle
-1

Eine praktische Erweiterung für die Änderung von animierten Schaltflächentiteln in Swift, die mit der Standardimplementierung gut funktioniert:

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)
    }
  }
}
Richard Topchii
quelle
@Fogmeister 1. Meine Antwort ist anders 2. Aktuelle Swift-Syntax 3. In Übereinstimmung mit Apples API für UIButton.
Richard Topchii