【问题标题】:Animate text Content in iOS - Equivalent for Android ValueAnimatoriOS 中的动画文本内容 - 等效于 Android ValueAnimator
【发布时间】:2023-03-03 22:16:01
【问题描述】:

我正在开发一个 iOS 7+ 应用程序,并希望以动画方式更改 UILabel 的内容。我想做任何图形动画,例如淡出旧内容/淡入新内容。因此,iOS 提供的所有标准动画功能(例如图层动画或动画块)都无法使用(至少我认为如此)。

假设 UILabel 显示一些仪表值,例如“200 V”,此文本应更改为“400 V”。文本不应该只是从“200 V”跳到“400 V”,而是应该使用一些缓动函数进行计数:“200 V”、“220 V”、“240 V”...“390 V”、“395 V" ... "400 V"

在 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 中也有这样的东西吗?我为此找到了不同的解决方案,但它们都很旧(2010/11)并且最终都使用 NSTimer 和自己的缓动函数手动实现了这种行为。

毫无疑问,一个人可以自己实现这一点,但这会很麻烦,也不是很优雅。那么:iOS 中有没有内置的东西可以解决这个问题,或者至少有方便的第三方实现可用?

非常感谢!

【问题讨论】:

  • 如果您已成功找到解决方案,请发布。
  • @TommieC。我使用了一个循环,但它不是很流畅,而且看起来很滞后。您找到解决方案了吗?
  • @JayVDiyk - 还没有找到简单的 iOS 解决方案,但我确实从 Core Animator 团队获得了这个示例:在终端窗口中从 bitbucket 克隆项目 ~ git clone mingsai@bitbucket.org/mingsai/odometer-sample.git
  • 看看stackoverflow.com/questions/14192816/…,我认为它回答了你的问题。

标签: ios animation


【解决方案1】:

因为我没有找到适合的解决方案,所以我创建了自己的:一个处理缓动的简单动画师类:

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

也许不是最漂亮的解决方案,但它有效:-)

【讨论】:

  • 太棒了!但我猜toble 中的- (void)animateValueFrom:(double)fromValue to:(toble)toValue 是一些特殊的数据结构? :P 或者它只是一个双 :)
  • 你不知道toble!?你是什​​么类型的开发者?你太无耻了!它是double 的一种特殊形式,只有最优秀的开发人员才知道。为了让其他人(包括你)更容易理解,我把它改成了普通的double... :-P
【解决方案2】:

我知道一个解决方案,但它用于快速迭代,因为最终迭代可以跳过值(如果搜索速度慢,看起来并不漂亮),但决策简单而简短,不能从架构中获得最漂亮的(但它可以必要时予以纠正)实现。

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

        });

    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 2017-01-22
    • 1970-01-01
    • 2013-10-18
    相关资源
    最近更新 更多