Jak animować właściwość textColor elementu UILabel?

82

Z jakiegoś powodu, kiedy próbuję animować textColor, to nie zadziała. TextColor po prostu nagle zmienia się z A na B. Czy można go animować, powiedzmy z czerwonego na czarny?

dontWatchMyProfile
źródło

Odpowiedzi:

6

Ta odpowiedź jest przestarzała i nie jest dobrym rozwiązaniem na pierwotne pytanie. Odpowiedź @strange poniżej jest znacznie lepsza i powinna być używana zamiast tej odpowiedzi: https://stackoverflow.com/a/20892927/76559

// Stara odpowiedź poniżej

textColorNieruchomość nie jest określony jako animatable w docs, więc nie sądzę, można to zrobić za pomocą prostego bloku animacji UIView ...

Można to prawdopodobnie zrobić dość prymitywnie, NSTimerwypalając co kilka milisekund, za każdym razem ustawiając kolor stopniowo od jednego do drugiego.

Mówię, że jest to surowe, ponieważ wymagałoby tablicy lub innego pojemnika z ustawionymi wartościami kolorów przechodzącymi od koloru początkowego do koloru końcowego, i jestem pewien, że jest sposób, aby to zrobić za pomocą podstawowej animacji lub czegoś podobnego, po prostu nie robię wiem, co to jest.

Jasarien
źródło
lub: funkcja, która wyrzuca tablicę z wartościami RGB między A i B oraz określoną wartością procentową. Nie wiem jednak nic o algorytmach kolorów.
dontWatchMyProfile
oto dobre obejścia: tu i tutaj dzięki Annie Kareninie
szakal
4
Należy CADisplayLinkraczej używać NSTimeranimacji jazdy niż ręcznie, ponieważ jest ona zsynchronizowana z aktualizacjami wyświetlania. Zobacz sesję 236 WWDC 2014: Interruptible and Responsive Interactions w budynku około godziny 13:00.
Douglas Hill
NIE powinna to być już akceptowana odpowiedź, nawet jeśli była prawdą w tamtym czasie. zobacz odpowiedź dziwnego poniżej
bitwit
1
Przepełnienie stosu nie pozwoli mi usunąć tej przestarzałej odpowiedzi, ponieważ została zaakceptowana. Odpowiedź Checkout @ dziwna poniżej.
Jasarien
196

Zamiast tego, jeśli próbowałeś użyć przejścia przenikania na samym obiekcie w ten sposób, da ci to ładny efekt zanikania z jednego koloru na drugi:

Cel C

[UIView transitionWithView:myLabel duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    myLabel.textColor = NEW_COLOR;
} completion:^(BOOL finished) {
}];

Szybki

UIView.transitionWithView(creditsLabel, duration: 0.25, options: .TransitionCrossDissolve, animations: {     
    self.creditsLabel.textColor = UIColor.redColor() 
}, 
completion: nil)

Jest to lepsze niż używanie NSTimerów, CATextLayers i tak dalej z różnych powodów. CATextLayer nie ma odpowiedniej obsługi kerningu tekstu ani NSAttributedText, a NSTimery są opóźnione (plus jest za dużo kodu). Powyższa animacja przejścia załatwia sprawę i może być również użyta w animacji łańcucha. Miałem ten sam problem i wypróbowałem już powyższe rozwiązania, ale zamiast tego ten prosty kod działa cuda.

dziwne
źródło
7
Ładne, eleganckie, właściwie najlepsze i najczystsze rozwiązanie.
maksa
17
Świetny. Działa w Swift tak samo:UIView.transitionWithView(creditsLabel, duration: 0.3, options: .TransitionCrossDissolve, animations: { self.creditsLabel.textColor = UIColor.redColor() }, completion: nil)
SimplGy
8
tylko uwaga: działa to tylko wtedy, gdy etykieta jest statyczna. Jeśli to zrobisz, a pozycja etykiety jest modyfikowana, animacja zanikania pokaże brzydki artefakt.
Lukas Petr,
Nie działa dla mnie na Xcode 10.2.1 i Swift 5. Poniższa metoda „shokaveli” działa
Martin
Szukałem sposobu, aby to zrobić w SwiftUI, ale wydaje się, że nie jest to obsługiwane w tym czasie.
philipp
58

Rozwiązanie Swift 4 :

UIView.transition(with: yourLabel, duration: 0.3, options: .transitionCrossDissolve, animations: {
  self.yourLabel.textColor = .red
}, completion: nil)
budiDino
źródło
Uwaga, działa to tylko wtedy, gdy masz wystąpienie UILabeldla withwłaściwości. Jeśli zrobisz coś podobnego transition(with: outerView.label…)i spróbujesz umieścić to w środku, po cichu zawiedzie.
Sam Soffes
Z jakiegoś powodu nie działa na mnie. Podczas animacji nagle zmienia się zamiast stopniowo. :(
ScottyBlades
1
@ScottyBlades może robisz animację w wątku w tle? Spróbuj opakować kod UIView.transition w nawiasy DispatchQueue.main.async {}.
budiDino
1
FYI - Pierwszy raz, kiedy próbowałem, nie zadziałał, a to dlatego options: .easeInOut, że tak było , więc zmieniłem to na .transitionCrossDissolve i działałem.
LeoGalante
13

Powodem, dla którego textColor nie można animować, jest to, że UILabel używa zwykłego CALayer zamiast CATextLayer.

Aby umożliwić animację textColor (jak również tekst, czcionkę itp.), Możemy utworzyć podklasę UILabel, aby używała CATextLayer.

To sporo pracy, ale na szczęście już to zrobiłem :-)

W tym artykule można znaleźć pełne wyjaśnienie + zastępczy zamiennik oprogramowania typu open source dla UILabel

adamsiton
źródło
9

Możesz spróbować utworzyć inną instancję UILabel lub cokolwiek innego, co ma textColor, a następnie zastosować animację między tymi dwoma instancjami (ze starym textColor i tym z nowym textColor).

benasher44
źródło
7

To była JEDYNA rzecz, która działała dla mnie:

let changeColor = CATransition()
changeColor.duration = 1

CATransaction.begin()

CATransaction.setCompletionBlock {
    selected.label.layer.addAnimation(changeColor, forKey: nil)
    selected.label.textColor = .blackColor()
}

selected.nameLabel.textColor = .redColor()

CATransaction.commit()
shokaveli
źródło
6

Oto mój kod do animacji koloru tekstu etykiety. Ważnym elementem jest ustalenie textColor do clearColor przed animacją

label.textColor = [UIColor clearColor];
[UIView transitionWithView:label duration:duration/4 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    label.textColor = self.highlightedCellPrimaryTextColor;
} completion:^(BOOL finished) { }];
servalex
źródło
0

Dość łatwo znalazłem umieszczenie UIView pod etykietą i animowanie jego krycia. Etykietę należy dodać do tego widoku. Może nie jest to dobre rozwiązanie z punktu widzenia zużycia zasobów, ale całkiem proste.

catchakos
źródło
0

zaktualizowany swift 3.0

Właśnie zmieniłem z komentarzy @budidino

UIView.transition(with: my.label, duration: 0.3, options: .transitionCrossDissolve, animations: { my.label.textColor = .black }, completion: nil)
Shawn Baek
źródło
0

Dzięki za odpowiedź @ Strange , działającą doskonale w Swift 5, Xcode 11 z niewielką zmianą składni. Animowałem kolor tekstu dla wielu etykiet UIL. Jeśli tak jest, spróbuj tego

for label in [label1, label2, ...] as [UILabel] { // loop through a @IBOutlet UILabel array
        UIView.transition(with: label, duration: 0.3, options: .transitionCrossDissolve, animations: {
            label.textColor = .label
        }, completion: nil)
}
Daniel Hu
źródło