円運動

円運動を10分くらいで書いてみたけど、
開始点の位置がなぜあそこなのかと、1週したら数秒停止する理由がわかんない。

とりあえず後で理由を調べるとしてコードを公開する。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
  // Override point for customization after application launch.
    
  [window makeKeyAndVisible];
    
  CGMutablePathRef path = CGPathCreateMutable();
  CALayer *layer = [CALayer layer];
  [window.layer addSublayer:layer];
  layer.bounds = CGRectMake(0, 0, 30, 30);
  layer.backgroundColor = [UIColor blueColor].CGColor;
  CGPathMoveToPoint(path, NULL, 0, 0);
  /*
  CGPathAddEllipseInRect(path, NULL, 
               CGRectMake(layer.bounds.size.width / 2, 
                    (window.frame.size.height - window.frame.size.width) / 2,
                    (window.frame.size.width - layer.bounds.size.width),
                    (window.frame.size.width - layer.bounds.size.width)));
  */
  // 時計周りかどうかの指定をする為に弧を使ってアニメーション
  CGRect rect = CGRectMake(
         layer.bounds.size.width / 2, 
         (window.bounds.size.height - window.bounds.size.width) / 2, 
         window.bounds.size.width - layer.bounds.size.width / 2, 
         window.bounds.size.width - layer.bounds.size.height / 2);
  CGPathAddArc(path, NULL, window.center.x, window.center.y, rect.size.width / 2, -M_PI_2, M_PI + 3 / 2, false);

  CAKeyframeAnimation *anim;
  anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  // ↓いらん
//  anim.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];
  // ↓これが必要 
  anim.calculationMode = @"cubicPaced"; // もしくは @"paced"
  anim.fillMode = kCAFillModeForwards;
  anim.path = path;
  anim.duration = 3.0f;
  anim.repeatCount = 1e100f;
  [layer addAnimation:anim forKey:@"MoveAnimation"];
  CGPathRelease(path);
  
    return YES;
}

[追記]
弧でアニメーションしてみた。
相変わらず開始点の指定ができていない。また最後の引数、clockwise = true のときに反時計周りでアニメーション終了時に停止、clockwise = falseのときはアニメーション終了時に停止しないという謎挙動 => 謎のまま。

[さらに追記]
原因解明。
caludurationMode = @"paced"もしくは@"cubicPaced" を指定すればなめらかに動いた。

ドキュメントを良く読めば以下のように書いてあった。

keyTimesプロパティは、各キーフレームセグメントの再生時間を定義する
NSNumberオブジェクトの配列を指定します。
配列内の各値は0.0から1.0までの浮動小数点数であり、values配列内の1つの
要素に対応します。keyTimes配列内の各要素は、対応するキーフレーム値の
再生時間を、そのアニメーションの合計再生時間に対する割合として定義し
ます。各要素の値は、直前の値よりも大きいか同じでなければなりません。

keyTimes配列の適切な値はcalculationModeプロパティに依存します。

* calculationModeがkCAAnimationLinearに設定されている場合、配列の
先頭の値は0.0で、最後の値は1.0となります。値は指定されたkeytimes
の間で補間されます。
* calculationModeがkCAAnimationDiscreteに設定されている場合、配列の
最初の値は0.0でなければなりません。
* calculationModeがkCAAnimationPacedに設定されるている場合、
keyTimes配列は無視されます。

なお、ヘッダファイル側を参照すれば、calculationModeは @"discrete", @"linear"(←デフォルト), @"paced", @"cubicPaced" を指定しろとある。kCA○○の中身を直接指定しろと勧めているのであろうか(笑)

以上、明日の勉強会(http://atnd.org/events/8386)でやってもいいかなと思ったのだが無事に解決してしまったのであった。