Help us understand the problem. What is going on with this article?

CADisplayLinkを使ったUILabelのアニメーション

More than 5 years have passed since last update.

はじめに

UILabelで数値をアニメーションしてカウントしたい場合の処理を
CADisplayLinkを使用して実装してみます。

UILabelサブクラスの作成

UILabelのサブクラスを作成します。例ではPMAnimationLabelという名前にしました。
そしてアニメーションを実行するメソッド(animationFrom:flag_to:withDuration:)を追加します。

PMAnimationLabel.h
@interface PMAnimationLabel : UILabel

-(void)animationFrom:(float)fromValue to:(float)toValue withDuration:(NSTimeInterval)duration;

@end

アニメーション処理の実装

PMAnimationLabel.mファイルにアニメーション処理を実装していきます。

PMAnimationLabel.m
//プロパティ
@interface PMAnimationLabel()
@property (nonatomic, assign) float startValue,endValue,rate,totaltime;
@property (nonatomic, assign) CFTimeInterval startTime;
@end

@implementation PMAnimationLabel

#pragma mark -- Class Method --

-(void)animationFrom:(float)fromValue to:(float)toValue withDuration:(NSTimeInterval)duration{
    self.startValue = fromValue; //アニメーション開始時の値
    self.endValue = toValue; //アニメーション終了時の値
    self.totaltime = duration; //アニメーションの時間

    self.text = [self getTextFromProgress:self.startValue];

    //CADisplayLinkの生成とコールバックの登録
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateValue:)];
    self.startTime = CACurrentMediaTime();
    [link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

#pragma mark -- Private Method --

-(void)updateValue:(CADisplayLink *)link{
    float dt = ([link timestamp] - self.startTime) / self.totaltime;
    if (dt >= 1.0) {
        self.text = [self getTextFromProgress:self.endValue];
        [link removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
        return;
    }

    float current = (self.endValue - self.startValue) * dt + self.startValue;
    self.text = [self getTextFromProgress:current];
}

-(NSString *)getTextFromProgress:(CGFloat)progress{
    return [NSString stringWithFormat:@"%i",percentage];
}

@end

アニメーションの実行

PMAnimationLabelを使用したいViewなどに追加してアニメーション用のメソッドを呼び出します。
(frameの設定、addSubView:などの処理は割愛します。)

PMAnimationLabel *animationLabel = [PMAnimationLabel new];
[animationLabel animationFrom:0 to:100 withDuration:3.0];

終わりに

CADisplayLinkはディスプレイのリフレッシュに同期してRunLoopを発生させるもののようで、
NSTimerと似たような実装が可能ですが、定期的な処理を実行する場合はCADisplayLinkの方が適切なようです。
(ここは自分もよく調べられてないので自信があまりないですが。。。)

参考資料

peromasamune
iOSがメインです(swift,Objective-C)。たまにAndroid、サーバーサイドなど(PHP, Ruby)
http://peromasamune.hateblo.jp/
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away