Animate text Content in iOS - Equivalent for Android ValueAnimator

后端 未结 2 1543
梦谈多话
梦谈多话 2021-01-04 07:02

I am working on an iOS 7+ app and would like to animated change the content of an UILabel. I do not want do do any graphical animation like fade out old con

2条回答
  •  被撕碎了的回忆
    2021-01-04 07:19

    Since I found no tailored solution for this I created my own: A simple Animator Class which handles the Easing:

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

    Maybe not the prettiest solution but it works :-)

提交回复
热议问题