2014-09-17 4 views
12

Ich arbeite an einer iOS 7+ App und möchte den Inhalt eines UILabel animiert ändern. I nicht wollen keine grafische Animation wie alten Inhalt ausblenden/neuen Inhalt einblenden. Somit können alle Standard-Animationsfeatures von iOS wie Layer-Animationen oder Animationsblöcke nicht verwendet werden (zumindest denke ich so).Animiere Text Inhalt in iOS - Equivalent für Android ValueAnimator

Angenommen, das UILabel zeigt einige Zählerwerte wie "200 V" an und dieser Text sollte auf "400 V" geändert werden. Der Text sollte nicht einfach von "200 V" auf "400 V" springen, sondern mit einer Beschleunigungsfunktion hochgezählt werden: "200 V", "220 V", "240 V" ... "390 V", "395 V“... "400 V"

in Android leicht gelöst werden könnten ValueAnimator mit:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); 
animation.setInterpolation(new EaseOutInterpolator()); 
animation.setDuration(2500); 
animation.setStartDelay(500); 

animation.addUpdateListener(new AnimatorUpdateListener() { 
    @Override 
    public void onAnimationUpate(ValueAnimator animator) { 
     float currentValue = animator.getAnimatedValue.floatValue(); 
     label1.setText(String.format("%.2", fromValue1 + ((toValue1 - fromValue1) * currentValue))); 
     label2.setText(String.format("%.2", fromValue2 + ((toValue2 - fromValue2) * currentValue))); 
    ... 
    } 
}); 
animation.start(); 

Ist so etwas in iOS auch dort? Ich habe dafür eine andere Lösung gefunden, aber sie sind alle ziemlich alt (2010/11) und alle implementieren dieses Verhalten manuell mit NSTimer und eigenen Beschleunigungsfunktionen.

Es steht außer Frage, dass man das alleine umsetzen kann, aber das wäre ziemlich umständlich und nicht sehr elegant. Also: Gibt es etwas in iOS gebaut, um dies zu lösen, oder gibt es zumindest praktische Drittanbieter-Implementierung zur Verfügung?

Vielen Dank!

+1

Bitte schreiben Sie, wenn Sie erfolgreich eine Lösung gefunden haben. –

+0

@TommieC. Ich benutzte eine Schleife, aber es ist nicht ganz glatt und es scheint Laggy. Haben Sie schon eine Lösung gefunden? – JayVDiyk

+0

@JayVDiyk - Es wurde noch keine einfache iOS-Lösung gefunden, aber ich habe dieses Beispiel vom Core Animator-Team erhalten: Im Terminal-Fenster klonen Sie das Projekt von bitbucket ~ ** git clone https: //[email protected]/mingsai/odometer-sample .git ** –

Antwort

3

Da fand ich keine maßgeschneiderte Lösung für dieses ich meine eigene erstellt: Eine einfache Animator-Klasse, die die Easing Griffe:

// MyValueAnimation.h 
typedef void (^MyAnimationBlock)(double animationValue); 

@interface MyValueAnimation : NSObject 

- (void)startAnimation:(MyAnimationBlock)animationBlock runtime:(NSUInteger)runtime delay:(NSUInteger)delay; 

@end 


// MyValueAnimation.m 
#import "MyValueAnimation.h" 

// Number of seconds between each animation step 
#define kStepSize 0.05 

@interface MyValueAnimation() { 
    NSTimer *timer;    
    NSUInteger totalRunTime; // Total duration of the animation (delay not included) 
    NSUInteger currentRuntime; // Time the animation is already running 
    MyAnimationBlock animationBlock; 
} 
@end 

@implementation MyValueAnimation 

- (void)startAnimation:(MyAnimationBlock)block runtime:(NSUInteger)runtime delay:(NSUInteger)delay { 
    if (timer != nil) 
     [timer invalidate]; 

    timer = nil; 
    totalRunTime = runtime; 
    animationBlock = block; 
    currentRuntime = 0; 

    if (block != nil) { 
     if (delay > 0) { 
      // Wait to delay the start. Convert delay from millis to seconds 
      double delaySeconds = (double)delay/1000.0; 
      timer = [NSTimer scheduledTimerWithTimeInterval:delaySeconds target:self selector:@selector(delayTick:) userInfo:nil repeats:false]; 
     } else { 
      // Run the animation 
      timer = [NSTimer scheduledTimerWithTimeInterval:kStepSize target:self selector:@selector(animationTick:) userInfo:nil repeats:true]; 
     } 
    } 
} 

- (void)delayTick:(NSTimer *)delayTimer { 
    // End of delay -> run animation 
    [delayTimer invalidate]; 
    timer = [NSTimer scheduledTimerWithTimeInterval:kStepSize target:self selector:@selector(animationTick:) userInfo:nil repeats:true]; 
} 

- (void)animationTick:(NSTimer *)animationTimer { 
    NSUInteger step = 1000 * kStepSize; // step size/length in milli seconds 
    currentRuntime += step; 
    double progress = MIN((double)currentRuntime/(double)totalRunTime, 1.0); 

    // Progress is a value between 0 and 1. The easing function maps this 
    // to the animationValue which is than used inside the animationBlock 
    // to calculate the current value of the animiation 
    double animationValue = [self customEaseOut:progress]; 

    if (animationBlock != nil) 
     animationBlock(animationValue); 

    if (progress >= 1.0) { 
     // Animation complete 
     [timer invalidate]; 
     timer = nil; 
    }   
} 

- (double)customEaseOut:(double)t { 
    // Use any easing function you like to animate your values... 
    // http://rechneronline.de/function-graphs/ 
    // http://sol.gfxile.net/interpolation/ 
    return (1 - pow(1-t, 2)); 
} 

@end 


// ============================================================= 

// Some code using the animation 
- (void)animateValueFrom:(double)fromValue to:(double)toValue { 
    if (valueAnimation == nil) 
     valueAnimation = [[MyValueAnimation alloc] init]; 

    MyAnimationBlock animationBlock = ^(double animationValue) { 
     double currentValue = fromValue + ((toValue - fromValue) * animationValue); 

     someLabel.text = [NSString stringWithFormat:"%dV", currentValue];   
    }; 

    [valueAnimation startAnimation:animationBlock runtime:1500 delay:500]; 
} 

Vielleicht nicht die schönste Lösung, aber es funktioniert :-)

+0

wunderbar! Aber ich vermute '' '' toble''' in Zeile '' '- (void) animateValueFrom: (double) fromValue to: (toble) toValue''' ist eine spezielle Datenstruktur? : P oder ist es nur ein Doppel :) –

+0

Sie wissen nicht, was ein 'toble' !? Was für ein Entwickler bist du? Schäm dich! Es ist eine spezielle Form von "double", die nur den besten Entwicklern bekannt ist. Um es für den Rest einfacher zu machen (einschließlich Sie), änderte ich es in ein gewöhnliches "Doppel" ... :-P –

1

Ich weiß, eine Lösung, aber es ist für schnelle Iteration, weil letzte Iterationen durch Wert springen können (sieht nicht schön aus, wenn es eine langsame Suche ist), aber die Entscheidung einfach und kurz, kann nicht die schönste von einer Architektur (aber es kann korrigiert werden, wenn es ist notwendige) Umsetzung.

- (void)someAction 
{ 
    [self animateValue:0 toValue:1111 withStep:7 andIntervalSpeed:5]; 
} 

-(void)animateValue:(int)value toValue:(int)toValue withStep:(int)step andIntervalSpeed:(int64_t)intervalSpeed 
{ 
    self.currentValue = value; // @property (nonatomic) int currentValue; 
    NSUInteger numberofIteration = (toValue - value)/step; 

    int64_t interval = 0.0; 
    for (NSUInteger i = 0; i < numberofIteration; i++) { 

     dispatch_time_t start = DISPATCH_TIME_NOW; 
     interval += intervalSpeed; 

     dispatch_after(dispatch_time(start, interval * USEC_PER_SEC), dispatch_get_main_queue(), ^{ 

      if (((toValue - value)%step != 0) && (i == (numberofIteration-1))) 
      { 
       self.currentValue = toValue; 
      } 
      else 
      { 
       self.currentValue+= step; 
      } 

      NSLog(@"%d",self.currentValue); 
      self.someLabel.text = [NSString stringWithFormat:@"%d",self.currentValue]; 

     }); 

    } 
} 
Verwandte Themen