CoreAnimationでCALayerを動かし続けたい時の方法です。プロパティ変更での暗黙的なアニメーションだといろいろと不都合なので、CABasicAnimationを使ってやってみました。
以下がそのサンプルです。カスタムビューにアウトレットをつなげて実行してください。
//
// EndlessCoreAnimationTest.h
//
#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
@interface EndlessCoreAnimationTest : NSObject {
IBOutlet NSView *view;
CALayer *moveLayer;
NSTimer *timer;
NSDate *startDate;
}
- (void)changeAnimation;
@end
//
// EndlessCoreAnimationTest.m
//
#import "EndlessCoreAnimationTest.h"
@implementation EndlessCoreAnimationTest
- (void)awakeFromNib
{
NSRect viewRect = [view bounds];
CGFloat viewWidth = viewRect.size.width;
CGFloat viewHeight = viewRect.size.height;
CGFloat minSize = (viewWidth > viewHeight) ? viewHeight : viewWidth;
CALayer *baseLayer = [CALayer layer];
CGColorRef baseColor = CGColorCreateGenericRGB(0.0, 0.0, 0.0, 1.0);
baseLayer.backgroundColor = baseColor;
CGColorRelease(baseColor);
moveLayer = [CALayer layer];
moveLayer.anchorPoint = CGPointMake(0.5, - 9.0);
moveLayer.bounds = CGRectMake(0, 0, minSize * 0.05, minSize * 0.05);
moveLayer.position = CGPointMake(viewWidth * 0.5, viewHeight * 0.5);
CGColorRef moveColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
moveLayer.backgroundColor = moveColor;
CGColorRelease(moveColor);
[view setLayer:baseLayer];
[view setWantsLayer:YES];
[baseLayer addSublayer:moveLayer];
[self performSelector:@selector(startTimer)
withObject:nil afterDelay:1.0];
}
- (void)startTimer
{
startDate = [[NSDate date] retain];
[self changeAnimation];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self selector:@selector(changeAnimation)
userInfo:nil repeats:YES];
}
- (void)changeAnimation
{
CGFloat currentTime = [startDate timeIntervalSinceNow];
CGFloat duration = 2.0;
CABasicAnimation *anim =
[CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D fromTrans =
CATransform3DMakeRotation(currentTime * M_PI / 4.0, 0.0, 0.0, 1.0);
CATransform3D toTrans =
CATransform3DMakeRotation((currentTime - duration) * M_PI / 4.0,
0.0, 0.0, 1.0);
anim.fromValue = [NSValue valueWithCATransform3D:fromTrans];
anim.toValue = [NSValue valueWithCATransform3D:toTrans];
anim.duration = duration;
[moveLayer addAnimation:anim forKey:@"transformAnimation"];
}
- (void) dealloc
{
[timer invalidate];
[startDate release];
[super dealloc];
}
@end
durationを2秒にしてtoValueを2秒後の値にしたCABasicAnimationを、NSTimerで1秒ごとに途切れる事無く追加しています。追加する時に動いているアニメーションの位置が新たなアニメーションのfromValueと一致するようになっていればスムーズにつながります。