Czy animować tekst UILabel między dwiema liczbami?

80

Jestem nowy w programowaniu na iPhone'a i Maca (wcześniej opracowanego dla systemu Windows) i mam pytanie:

Jak ożywić textwłaściwość UILabelpomiędzy dwoma liczbami, np. Od 5 do 80 w stylu Ease-Out? Czy to możliwe CoreAnimation? Szukałem w Google od godziny, ale nie znalazłem nic, co rozwiązałoby mój problem. Czego chcę: Animuj pieniądze użytkowników na prostą grę. Nie wygląda to zbyt ładnie, gdy po prostu wzrasta od 50 do 100 lub coś w tym rodzaju bez animacji.

Czy ktoś ma pomysł, jak to zrobić?

Dzięki!

Markus Kasten
źródło
2
To stare pytanie, ale Pop (framework animacji na Facebooku) byłby dobrym rozwiązaniem. Możesz bezpośrednio animować właściwość text.
jrturton
Prawdopodobnie duplikat zmiany tekstu w programie Animate w UILabel
eonil

Odpowiedzi:

160

Możesz użyć automatycznych przejść. Działa doskonale:

// Add transition (must be called after myLabel has been displayed)
 CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionFade;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:@"changeTextTransition"];

// Change the text
myLabel.text = newText;

Ten kod działa, jeśli myLabel jest już wyświetlona. Jeśli nie, myLabel.layer będzie zerowe i animacja nie zostanie dodana do obiektu.


w Swift 4 byłoby to:

let animation: CATransition = CATransition()
animation.duration = 1.0
animation.type = kCATransitionFade
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
myLabel.layer.add(animation, forKey: "changeTextTransition")
CedricSoubrie
źródło
2
Próbowałem tego (upewniając się, że warstwa nie jest zerowa po dodaniu animacji), ale tekst nadal nie jest animowany. Jakieś inne pułapki?
elsurudo
5
Na marginesie, musisz dodać animację tuż przed zmianą tekstu za każdym razem, gdy chcesz zmienić tekst i uzyskać efekt zanikania. Nie musisz jednak za każdym razem tworzyć nowej instancji przejścia, ta sama instancja może być wielokrotnie używana.
Lance
2
Chodziło o to, jak ożywić liczby, np. Zwiększając ich wartość, a nie graficznie między nimi. Użyj PRTween: github.com/shu223/TweenDemo/tree/…
jowie
14
Właściwie, jeśli ustawisz removedOnCompletionsię NOna wystąpienie CATransition, każda zmiana etykiety textbędą animowane.
Mark Adams
1
@kientux W kluczu nie ma nic specjalnego changeTextTransition. Jest to po prostu ciąg identyfikujący animację , co oznacza, że ​​jest to ciąg, którego możesz później użyć do zidentyfikowania animacji, którą wcześniej dodałeś. Jeśli nie musisz później identyfikować animacji, możesz po prostu określić nil.
jamesk
27

To dobrze działa!

Cel C

[UIView transitionWithView:self.label 
                  duration:.5f 
                   options:UIViewAnimationOptionCurveEaseInOut | 
                           UIViewAnimationOptionTransitionCrossDissolve 
                animations:^{

    self.label.text = rand() % 2 ? @"111!" : @"42";

} completion:nil];

Szybki 2

UIView.transitionWithView(label, duration: 0.25, options: [.CurveEaseInOut, .TransitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)

Swift 3, 4, 5

UIView.transition(with: label, duration: 0.25, options: [.curveEaseInOut, .transitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)
Anton Gaenko
źródło
1
Pracował również dla innych nieruchomości, takich jak zmiana imageaUIImageView
SaltyNuts
7

Znalazłem świetny silnik do animowania wartości z różnymi różnymi funkcjami czasowymi zwanymi PRTween . Zainstaluj klasy i utwórz kod według tych linii:

- (IBAction)tweenValue
{
    [[PRTween sharedInstance] removeTweenOperation:activeTweenOperation];
    PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:0.0 endValue:100.0 duration:1.0];
    activeTweenOperation = [[PRTween sharedInstance] addTweenPeriod:period
                                                             target:self
                                                           selector:@selector(update:)
                                                     timingFunction:&PRTweenTimingFunctionCircOut];
}

- (void)update:(PRTweenPeriod*)period
{
    self.animatingView.center = CGPointMake(period.tweenedValue + 100.0, 200.0);
    self.valueLabel.text = [NSString stringWithFormat:@"%.2f", period.tweenedValue];
}

To dla mnie prawdziwa uczta. :)

jowie
źródło
5

Jeśli chcesz, aby liczył w górę iw dół, a nowa liczba odpycha poprzednią liczbę (jak ticker lub coś takiego):

let animation = CATransition()
animation.removedOnCompletion = true
animation.duration = 0.2
animation.type = kCATransitionPush
animation.subtype = newValue > value ? kCATransitionFromTop : kCATransitionFromBottom
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
valueLabel.layer.addAnimation(animation, forKey:"changeTextTransition")
Adam Waite
źródło
Hej! Dzięki za odpowiedź! To działa całkiem nieźle. Mam tylko dalsze pytania. Czy wiesz, jak animować tylko części tekstu? Podoba Ci się trzecia postać i czy reszta pozostanie niezmieniona? Chciałbym zaimplementować etykietę pokazującą liczby. Jeśli wartość się zmieni, tylko cyfry będą animowane, co faktycznie się zmieniło.
Lars Petersen
Osobiście przyjrzałbym się używaniu CoreGraphics i CoreAnimation do tego typu rzeczy. A może możesz oszukiwać i łączyć ze sobą kilka etykiet? Zależy od stopnia złożoności ciągu.
Adam Waite,
3

W Swift 2.0 przy użyciu UIView.transitionWithView()metody:

UIView.transitionWithView(self.payPeriodSummaryLabel,
        duration: 0.2,
        options: [.CurveEaseInOut, .TransitionCrossDissolve],
        animations: { () -> Void in
            self.label.text = "your text value"
        }, completion: nil)
brandonscript
źródło
1

kolejna prosta alternatywa

extension UILabel {    
    func countAnimation(upto: Double) {
        let from: Double = text?.replace(string: ",", replacement: ".").components(separatedBy: CharacterSet.init(charactersIn: "-0123456789.").inverted).first.flatMap { Double($0) } ?? 0.0
        let steps: Int = 20
        let duration = 0.350
        let rate = duration / Double(steps)
        let diff = upto - from
        for i in 0...steps {
            DispatchQueue.main.asyncAfter(deadline: .now() + rate * Double(i)) {
                self.text = "\(from + diff * (Double(i) / Double(steps)))"
            }
        }
    }
}
Sergio
źródło