在iOS中为文字添加animation内容 – 等同于Android的ValueAnimator

我正在使用iOS 7+应用程序,并希望animation更改UILabel的内容。 我不想做像淡出旧内容/淡入新内容的任何graphicsanimation。 因此,iOS提供的所有标准animationfunction(如animation或animation块)都无法使用(至less我是这么认为的)。

假设UILabel显示一些电表值,如“200 V”,这个文本应该改为“400 V”。 文本不应该从“200 V”跳到“400 V”,而应该使用一些缓冲function:“200 V”,“220 V”,“240 V”…“390 V”,“395 V“…”400V“

在Android中可以很容易地使用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(); 

iOS中也有这样的事情吗? 我发现不同的解决scheme,但他们都很老(2010/11年),所有最终实现这种行为手动使用NSTimer和自己的缓和function。

可以自己实现这一点是毫无疑问的,但是这样做会很麻烦,不够高雅。 所以:有没有什么内置的iOS来解决这个问题,还是至less有方便的第三方实现?

非常感谢你!

因为我没有find适合的解决scheme,所以我创build了自己的:一个简单的animation类,处理缓和:

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

也许不是最漂亮的解决scheme,但它的工作原理:-)

我知道一个解决scheme,但它的快速迭代,因为最后的迭代可以跳过价值(看起来不是很漂亮,如果有一个缓慢的search),但决策简单和短,不能从架构最美丽(但它可以纠正,如果有必要)实现。

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