Posted at

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の方が適切なようです。

(ここは自分もよく調べられてないので自信があまりないですが。。。)


参考資料