【Xcode】UIBezierPathをアニメーションで描画

【Xcode6.2 + iOS 8.4(iPhone5) + MacOX10.9.5】

UIBezierPathはベジェ曲線を描画するクラスですが、この描画そのものをアニメーションさせられないかと調べてみました。

まずはUIBezierPathの使い方、この辺が参考になります。
[iPhone] UIBezierPath 図形の描画 (Objective-C)
[Swift] UIBezierPathを使って、直線、楕円、矩形などで描画する
UIBezierPathで曲線を描画してみた | 丸ノ内テックブログ
UIBezierPathで図形を描画する。: iPhoneソースコードがきたなくて

で、実際に書いてみたのがこちら。

iOS Simulator Screen Shot 2015.10.05 3.03.25
UIBezierPathでローディング的な円を描いてみた。

コードはこんな感じ。

・CircleView.h

//
//  CircleView.h
//  testUIBezierPath
//
//  Created by c-geru on 2015/10/04.
//  Copyright (c) 2015年 c-geru. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface CircleView : UIView

@end

・CircleView.m

//
//  CircleView.m
//  testUIBezierPath
//
//  Created by c-geru on 2015/10/04.
//  Copyright (c) 2015年 c-geru. All rights reserved.
//

#import "CircleView.h"

@implementation CircleView

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // 円弧 -------------------------------------
    UIBezierPath* arc
    = [UIBezierPath bezierPathWithArcCenter:
       CGPointMake(self.frame.size.width/2,self.frame.size.height/2) radius:125.0f startAngle:M_PI/2*-1 endAngle:M_PI*2 clockwise:YES];
    UIColor *aColor = [UIColor lightGrayColor];
    [aColor setStroke];
    arc.lineWidth = 10;
    // 点線のパターンをセット
    CGFloat dashPattern[2] = { 2.0f, 4.0f };
    [arc setLineDash:dashPattern  count:2 phase:0];
    [arc stroke];

    // 円弧 (アニメーション)-------------------------------------
    UIBezierPath* arc2
    = [UIBezierPath bezierPathWithArcCenter:
       CGPointMake(self.frame.size.width/2,self.frame.size.height/2) radius:125.0f startAngle:M_PI/2*-1 endAngle:M_PI*4/4 clockwise:YES];

    UIColor *aColor2 = [UIColor blueColor];
    [aColor2 setStroke];

    arc2.lineWidth = 10;
    // 点線のパターンをセット
    CGFloat dashPattern2[2] = { 2.0f, 4.0f };
    [arc2 setLineDash:dashPattern2  count:2 phase:0];
    [arc2 stroke];
}
@end

で、この青い部分をローディングバー的にアニメーションしたかったわけです。

基本的にアニメーションはCALayerってことはわかったんだけど、アニメーションさせるためのパラメタの渡し方がよくわかりませんでした。

iPhone – パスに沿ってアニメーションさせる – Qiita
CALayerを使ってアニメーションしよう – make.appアプリ開発Tips

更に調べてみると、描画要素(fillColor,strokeColor,lineWidth,lineDashPattern)をUIBezierPathでなく、CALayer側に渡してあげればいいみたい。アニメーションで描画するので、考えてみれば当然か。

iOS Development Tricks: Custom Circular Progress View for iOS
CAShapeLayer example – Round corners view with dashed line border | Luka Gabric

最終的にアニメーションできたコードがコレ。

・CircleView.h

//
//  CircleView.h
//  testUIBezierPath
//
//  Created by c-geru on 2015/10/04.
//  Copyright (c) 2015年 c-geru. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface CircleView : UIView

@end

・CircleView.m

//
//  CircleView.m
//  testUIBezierPath
//
//  Created by c-geru on 2015/10/04.
//  Copyright (c) 2015年 c-geru. All rights reserved.
//

#import "CircleView.h"

@implementation CircleView

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // 円弧 -------------------------------------
    UIBezierPath* arc
    = [UIBezierPath bezierPathWithArcCenter:
       CGPointMake(self.frame.size.width/2,self.frame.size.height/2) radius:125.0f startAngle:M_PI/2*-1 endAngle:M_PI*2 clockwise:YES];
    UIColor *aColor = [UIColor lightGrayColor];
    [aColor setStroke];
    arc.lineWidth = 10;
    // 点線のパターンをセット
    CGFloat dashPattern[2] = { 2.0f, 4.0f };
    [arc setLineDash:dashPattern  count:2 phase:0];
    [arc stroke];

    // 円弧 (アニメーション)-------------------------------------
    UIBezierPath* arc2
    = [UIBezierPath bezierPathWithArcCenter:
       CGPointMake(self.frame.size.width/2,self.frame.size.height/2) radius:125.0f startAngle:M_PI/2*-1 endAngle:M_PI*4/4 clockwise:YES];

    if (self.pathLayer == nil)
    {
        CAShapeLayer *shapeLayer = [CAShapeLayer layer];

        shapeLayer.path = [arc2 CGPath];

        shapeLayer.fillColor = [UIColor clearColor].CGColor;
        shapeLayer.strokeColor = [UIColor blueColor].CGColor;
        shapeLayer.lineWidth = 10;

        shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:2], [NSNumber numberWithInt:4], nil];

        [self.layer addSublayer:shapeLayer];
        self.pathLayer = shapeLayer;
    }

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAnimation.duration = 3.0;
    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0];
    [self.pathLayer addAnimation:pathAnimation forKey:@"drawCircleAnimation"];
}
@end