Jak zapobiec miganiu UIButton podczas aktualizacji tytułu

85

Kiedy wywołuję setTitle na UIButton, przycisk miga w iOS 7. Próbowałem ustawić myButton.highlighted = NIE, ale to nie powstrzymało migania przycisku.

[myButton setTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"elapsedLabelKey"] forState:UIControlStateNormal];

myButton.highlighted = NO;

Oto jak ustawiłem licznik czasu, który aktualizował tytuły:

- (void)actionTimer {
    if (myTimer == nil) {

        myTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0
                        target: self
                        selector: @selector(showActivity)
                        userInfo: nil
                        repeats: YES];
    }
}

Oto metoda, która faktycznie aktualizuje tytuły:

- (void)showActivity {

    NSString *sym = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];

    if (pauseInterval == nil) {

        // Update clock
        seconds = [[NSDate date] timeIntervalSinceDate:startInterval] - breakTime;

        // Update total earned
        secRate = rate.value / 60 / 60;
        total = secRate * seconds;
        [totalLabel setTitle:[NSString stringWithFormat:@"%@%.4f",sym,total] forState:UIControlStateNormal];

        days = seconds / (60 * 60 * 24);
        seconds -= days * (60 * 60 * 24);
        int hours = seconds / (60 * 60);
        fhours = (float)seconds / (60.0 * 60.0);
        seconds -= hours * (60 * 60);
        int minutes = seconds / 60;
        seconds -= minutes * 60;

        // Update the timer clock
        [elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
    }
}
FierceMonkey
źródło
Nie powinno migać. Czy próbujesz to zrobić w wątku w tle?
BergQuester,
Tak, jest ustawiony w
liczniku
Timery działają tylko w osobnym wątku, jeśli tak je skonfigurujesz. Czy moglibyśmy zobaczyć metodę, w której tytuł jest aktualizowany i jak ustawiasz licznik czasu?
BergQuester
Dodałem żądany kod do głównego pytania
FierceMonkey

Odpowiedzi:

205

Ustaw typ przycisku na UIButtonTypeCustom i przestanie migać

Quanlong
źródło
16
To naprawdę powinna być preferowana odpowiedź. Najprostsze rozwiązanie. I to działa.
Johan Karlsson
4
Zgoda. Wypróbowałem wiele innych rozwiązań i to jest rzecz, która to zrobiła, sama.
BBQ Steve
2
To powinna być akceptowana odpowiedź. Jak dotąd najprostsze rozwiązanie.
Machado
1
Działa jak marzenie! Dzięki
2
Myślę, że to naprawdę dobre rozwiązanie bez pisania do tego żadnego kodu.
Chauyan
55

Lepszym podejściem niż to, [UIView setAnimationsEnabled:NO]które może wpłynąć na inne animacje, jest wyłączenie tylko określonej animacji tytułu.

Cel C:

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

Szybki:

UIView.performWithoutAnimation { 
    myButton.setTitle(text, for: .normal)
    myButton.layoutIfNeeded()
}
Cœur
źródło
Właśnie wypróbowałem rozwiązanie Swift na najnowszym iOS - działa świetnie.
Ronen Rabinovici
1
Zbawiciel dnia. Twoje zdrowie!
pkc456
Właśnie wypróbowałem to w Swift 3 i działa bez użycia layoutIfNeeded ()
user1898712
3
To powinna być bez wątpienia akceptowana odpowiedź!
Julius
1
To najlepszy sposób, aby to zrobić. Świetna odpowiedź!
koniec
29

* Uwaga *

gdy „ buttonType ” _button to „UIButtonTypeSystem” , poniższy kod jest nieprawidłowy

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

gdy „ buttonType ” _button to „UIButtonTypeCustom” , powyższy kod jest prawidłowy .

shede333
źródło
19

Zobacz odpowiedzi z Jak zatrzymać niechcianą animację UIButton przy zmianie tytułu? :

[UIView setAnimationsEnabled:NO];
[elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];
Marius
źródło
7
@FierceMonkey spróbuj dodać wywołanie layoutIfNeeded: [elapsed layoutIfNeeded];. To usunęło mruganie w moim przypadku.
Klaas
1
layoutIfNeeded zrobił to za mnie.
Kaolin Fire
Wydaje się, że jest to raczej brudne obejście, ale layoutIfNeededwydaje się działać
Przemysław Wrzesiński
7

Możesz po prostu utworzyć kolejną funkcję dla UIButton, która będzie łatwa w użyciu w przyszłości.

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

To jest to!

I po prostu ustawić tytuł jak byś wcześniej, ale zastąpić setTitlezsetTitleWithoutAnimation

Daniel Tseng
źródło
6

Domyślne zachowanie "setTitle" jest zdecydowanie nienawistne!

Moje rozwiązanie to:

[UIView setAnimationsEnabled:NO];
[_button layoutIfNeeded]; 
[_button setTitle:[NSString stringWithFormat:@"what" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Również w scenorysie, pod właściwością przycisku odznaczam:

  • Odwraca się po podświetleniu
  • Podświetlony Dopasuj obraz

I zaznacz:

  • Wyłączone Dostosuj obraz

Przetestowany i działający również na iOS 8 .

Aktualizacja - Swift

Sugeruję utworzenie własnego przycisku i zastąpienie metody setTitle .

class UnflashingButton: UIButton {
   
    override func setTitle(title: String?, forState state: UIControlState) {
        UIView.setAnimationsEnabled(false)
        self.layoutIfNeeded()
        super.setTitle(title, forState: state)
        UIView.setAnimationsEnabled(true)
    }

}
Luca Davanzo
źródło
Wypróbowałem to podejście (podklasy, przesłanianie setTitle: forState: i wyłączanie - włączanie UIView.setAnimationsEnabled). Nie działa dla mnie w iOS 9 i 10 beta. Działa, jeśli
wyłączę
2

Spróbuj tego, to działa w nowszych wersjach IOS:

class CustomButtonWithNoEffect : UIButton {
    override func setTitle(_ title: String?, for state: UIControlState) {
        UIView.performWithoutAnimation {
            super.setTitle(title, for: state)
            super.layoutIfNeeded()
        }
    }

}
Kárpáti András
źródło
0

Jestem nowy w kodowaniu i Stackoverflow, więc nie mam wystarczającej reputacji, aby komentować bezpośrednio, aby rozwinąć https://stackoverflow.com/users/4673064/daniel-tseng doskonałą odpowiedź. Muszę więc napisać własną nową odpowiedź, a jest ona taka:

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

Działa świetnie, Z WYJĄTKIEM:

Jeśli wszystkie moje wywołania później w kodzie „setTitleWithoutAnimation” nie określają nadawcy, otrzymuję te dziwne komunikaty związane z CoreMedia lub CoreData, np. „Nie udało się dziedziczyć uprawnień CoreMedia z 2526: (null)”

Jest to prawdopodobnie dość podstawowe dla kodowania i iOS, ale dla mnie, jako nowego programisty, wysłało mnie na jakiś czas na ślad królika, jak w: Today Extension Failed to dziedziczyć uprawnienia CoreMedia od , gdzie ludzie mieli ciekawe odpowiedzi, ale to NIE dotrzeć do źródła mojego problemu.

Więc w końcu stwierdziłem, że muszę przejść i podać parametry funkcji bez parametrów, tj. Musiałem określić nadawcę. Tym nadawcą może być UIButton, Any lub AnyObject. Wszystkie z nich zadziałały, ale ostatecznie wydaje się, że istnieje konflikt między dodaniem rozszerzenia przycisku za pomocą „siebie” a nie mówieniem później konkretnie, że przycisk go używa.

Ponownie, prawdopodobnie podstawowe, ale dla mnie nowe, więc pomyślałem, że warto się tym podzielić.

Ian Hanson
źródło
0

Kolejna sztuczka

@IBOutlet private weak var button: UIButton! {
    didSet {
        button.setTitle(title, for: .normal)
    }
}

Działa to tylko wtedy, gdy znasz wartość tytułu bez wykonywania żadnych wywołań API. Tytuł przycisku zostanie ustawiony przed załadowaniem widoku, więc nie zobaczysz animacji

TunaTheDog
źródło