2014-09-17 15 views
12

Pracuję nad aplikacją iOS 7+ i chcę animować zmienić zawartość UILabel. I Do not Chcę zrobić graficzną animację, taką jak wyciszanie starej treści/zanikanie nowej zawartości. Zatem wszystkie standardowe animacje oferują takie oferty iOS jak animacje warstwowe lub bloki animacji, które nie mogą być wykorzystane (przynajmniej tak myślę).Treść animacji Treść w systemie iOS - Równoważna dla Androida ValueAnimator

Założono, że UILabel pokazuje niektóre wartości mierników, takie jak "200 V", a tekst ten należy zmienić na "400 V". Tekst nie powinien po prostu przeskakiwać z "200 V" na "400 V", ale powinien być zliczany za pomocą funkcji łagodzenia: "200 V", "220 V", "240 V" ... "390 V", "395 V”... "400 V"

w Androidzie można łatwo rozwiązać za pomocą ValueAnimator:

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

Czy istnieje coś takiego w iOS, jak również? Znalazłem inne rozwiązanie, ale wszystkie są dość stare (2010/11) i wszystkie kończą wdrażanie tego zachowania ręcznie przy użyciu NSTimer i własnych funkcji rozluźniających.

Jest wykluczone, że można to wdrożyć na własną rękę, ale byłoby to dość kłopotliwe i niezbyt eleganckie. A więc: Czy jest coś, co można zbudować na iOS, aby to rozwiązać, czy też jest dostępna przynajmniej wygodna implementacja strony trzeciej?

Dziękuję bardzo!

+1

Proszę pisać, jeśli udało Ci się znaleźć rozwiązanie. –

+0

@ TommieC. Użyłem pętli, ale nie jest ona całkiem gładka i wydaje się opóźniona. Znalazłeś już rozwiązanie? – JayVDiyk

+0

@JayVDiyk - Nie znaleziono jeszcze prostego rozwiązania dla systemu iOS, ale dostałem próbkę od zespołu Core Animator: W oknie terminala sklonuj projekt z bitbucket ~ ** git clone https: //[email protected]/mingsai/odometer-sample .git ** –

Odpowiedz

3

Ponieważ znalazłem żadnego rozwiązania dopasowane do tego tworzę własne: prosty Animator klasy, która obsługuje złagodzenie:

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

może nie najładniejszy rozwiązanie, ale to działa :-)

+0

cudownie! Ale myślę, że '' toble''' w linii '' '- (void) animateValueFrom: (double) fromValue do: (toble) toValue''' jest jakąś specjalną strukturą danych? : P czy to tylko podwójne :) –

+0

Nie wiesz, co to jest "tobol" !? Jakim jesteś programistą? Wstydź się! Jest to specjalna forma "podwójnego", znana tylko najlepszym programistom. Aby ułatwić zrozumienie dla reszty (łącznie z tobą), zmieniłem ją na zwykłą "podwójną" ... :-P –

1

wiem rozwiązanie, ale do szybkiej iteracji, ponieważ końcowe iteracje mogą przeskakiwać przez wartość (wygląda nie pięknie, jeśli jest wolne wyszukiwanie), ale decyzja prosta i krótka, nie może być najpiękniejsza z architektury (ale może być poprawiona, jeśli jest konieczne) realizacja.

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

     }); 

    } 
} 
Powiązane problemy