iPhone黄金長方形アプリ

黄金長方形の作図法をアニメーションで表示する電子テキストのようなiPhoneアプリを作成してみます。黄金長方形とは、神聖比例とよばれる比率をもつ長方形のことです。この比率はだいたい1:1.618です。


動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。

ポイント
1.618という数値を使って、正方形から黄金長方形を書く方法などをアニメーションさせています。線はCAShapeLayerとUIBezierPathで描いていて、アニメーションはanimationWithKeyPathでstrokeEndを指定することで指定の秒数でパスを描くようにしました。

サンプルコード

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

@interface ViewController () {

    UILabel *message;

    NSMutableArray *shapes;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    self.view.backgroundColor = [UIColor whiteColor];

    

    [self createButtons];

    

    [self createMessage];

    

    shapes = [[NSMutableArray alloc] init];

}

– (void)createButtons

{

    float size = 320.0 / 4.0;

    for (int i=0; i<4; i++) {

        float x = size * i;

        float y = 350;

        UILabel *btn = [[UILabel alloc] initWithFrame:CGRectMake(x, y, size, size)];

        btn.text = [NSString stringWithFormat:@”%d”, i + 1];

        btn.textAlignment = 1;

        btn.textColor = [UIColor whiteColor];

        btn.font = [UIFont systemFontOfSize:size – 10];

        btn.backgroundColor = [UIColor blackColor];

        btn.layer.borderWidth = 5;

        btn.layer.borderColor = [UIColor whiteColor].CGColor;

        [self.view addSubview:btn];

        

        btn.userInteractionEnabled = YES;

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];

        [btn addGestureRecognizer:tap];

    }

}

– (void)createMessage

{

    message = [[UILabel alloc] initWithFrame:CGRectMake(5, 280, 310, 50)];

    message.backgroundColor = [UIColor blackColor];

    message.textColor = [UIColor whiteColor];

    message.textAlignment = 1;

    [self.view addSubview:message];

}

– (void)tap:(UITapGestureRecognizer*)gr

{

    int number = [((UILabel*)gr.view).text intValue];

    switch (number) {

        case 1:

            [self drawSquare];

            break;

        case 2:

            [self drawGoldenRectangle];

            break;

        case 3:

            [self drawSeparate];

            break;

        case 4:

            [self drawSeparate2];

            break;

        default:

            break;

    }

}

– (void)drawSquare

{

    [self clearShapes];

    

    message.text = @”1.正方形を描く;

    

    float size = 150;

    CGPoint start = CGPointMake(40, 50);

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:start];

    [path addLineToPoint:CGPointMake(start.x + size, start.y)];

    [path addLineToPoint:CGPointMake(start.x + size, start.y + size)];

    [path addLineToPoint:CGPointMake(start.x, start.y + size)];

    [path addLineToPoint:start];

    

    CAShapeLayer *sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor blackColor].CGColor;

    sl.lineWidth = 2;

    sl.path = path.CGPath;

    

    [shapes addObject:sl];

    [self drawShapesWithAnimation:sl];

}

– (void)drawGoldenRectangle

{

    [self clearShapes];

    

    message.text = @”2.辺の中点から弧 -> 黄金長方形;

    

    float size = 150;

    CGPoint start = CGPointMake(40, 50);

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:start];

    [path addLineToPoint:CGPointMake(start.x + size, start.y)];

    [path addLineToPoint:CGPointMake(start.x + size, start.y + size)];

    [path addLineToPoint:CGPointMake(start.x, start.y + size)];

    [path addLineToPoint:start];

    CAShapeLayer *sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor blackColor].CGColor;

    sl.lineWidth = 2;

    sl.path = path.CGPath;

    [self.view.layer addSublayer:sl];

    

    

    UIBezierPath *path2 = [UIBezierPath bezierPath];

    CGPoint mid = CGPointMake(start.x + size/2.0, start.y + size);

    float r = hypotf(size/2.0, size);

    float startAngle = atan2f(-size, size/2.0);

    [path2 moveToPoint:mid];

    [path2 addArcWithCenter:mid radius:r startAngle:startAngle endAngle:0 clockwise:YES];

    

    CAShapeLayer *sl2 = [[CAShapeLayer alloc] init];

    sl2.fillColor = [UIColor clearColor].CGColor;

    sl2.strokeColor = [UIColor redColor].CGColor;

    sl2.lineWidth = 2;

    sl2.lineDashPattern = @[@5, @5];

    sl2.path = path2.CGPath;

    

    

    UIBezierPath *path3 = [UIBezierPath bezierPath];

    float gWidth = size * 1.618;

    [path3 moveToPoint:CGPointMake(start.x + size, start.y + size)];

    [path3 addLineToPoint:CGPointMake(start.x + gWidth, start.y + size)];

    [path3 addLineToPoint:CGPointMake(start.x + gWidth, start.y)];

    [path3 addLineToPoint:CGPointMake(start.x + size, start.y)];

    

    CAShapeLayer *sl3 = [[CAShapeLayer alloc] init];

    sl3.fillColor = [UIColor clearColor].CGColor;

    sl3.strokeColor = [UIColor redColor].CGColor;

    sl3.lineWidth = 2;

    sl3.path = path3.CGPath;

    

    

    [shapes addObject:sl];

    [shapes addObject:sl2];

    [shapes addObject:sl3];

    

    [self drawShapesWithAnimation:sl2];

    [self performSelector:@selector(drawShapesWithAnimation:) withObject:sl3 afterDelay:3.0];

}

– (void)drawSeparate

{

    [self clearShapes];

    

    message.text = @”3.黄金長方形の分割;

    

    float size = 150;

    float gWidth = size * 1.618;

    CGPoint start = CGPointMake(40, 50);

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:start];

    [path addLineToPoint:CGPointMake(start.x + gWidth, start.y)];

    [path addLineToPoint:CGPointMake(start.x + gWidth, start.y + size)];

    [path addLineToPoint:CGPointMake(start.x, start.y + size)];

    [path addLineToPoint:start];

    CAShapeLayer *sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor blackColor].CGColor;

    sl.lineWidth = 2;

    sl.path = path.CGPath;

    [self.view.layer addSublayer:sl];

    

    UIBezierPath *path2 = [UIBezierPath bezierPath];

    [path2 moveToPoint:CGPointMake(start.x, start.y + size)];

    [path2 addLineToPoint:CGPointMake(start.x + gWidth, start.y)];

    CAShapeLayer *sl2 = [[CAShapeLayer alloc] init];

    sl2.fillColor = [UIColor clearColor].CGColor;

    sl2.strokeColor = [UIColor redColor].CGColor;

    sl2.lineWidth = 2;

    sl2.lineDashPattern = @[@5, @5];

    sl2.path = path2.CGPath;

    

    UIBezierPath *path3 = [UIBezierPath bezierPath];

    [path3 moveToPoint:CGPointMake(start.x + size, start.y)];

    [path3 addLineToPoint:CGPointMake(start.x + size, start.y + size)];

    CAShapeLayer *sl3 = [[CAShapeLayer alloc] init];

    sl3.fillColor = [UIColor clearColor].CGColor;

    sl3.strokeColor = [UIColor blackColor].CGColor;

    sl3.lineWidth = 2;

    sl3.path = path3.CGPath;

    

    UIBezierPath *path4 = [UIBezierPath bezierPath];

    [path4 moveToPoint:CGPointMake(start.x + size, start.y)];

    [path4 addLineToPoint:CGPointMake(start.x + gWidth, start.y + size)];

    CAShapeLayer *sl4 = [[CAShapeLayer alloc] init];

    sl4.fillColor = [UIColor clearColor].CGColor;

    sl4.strokeColor = [UIColor redColor].CGColor;

    sl4.lineWidth = 2;

    sl4.lineDashPattern = @[@5, @5];

    sl4.path = path4.CGPath;

    

    [shapes addObject:sl];

    [shapes addObject:sl2];

    [shapes addObject:sl3];

    [shapes addObject:sl4];

    

    [self drawShapesWithAnimation:sl2];

    [self performSelector:@selector(drawShapesWithAnimation:) withObject:sl3 afterDelay:3.0];

    [self performSelector:@selector(drawShapesWithAnimation:) withObject:sl4 afterDelay:6.0];

}

– (void)drawSeparate2

{

    [self clearShapes];

    

    message.text = @”4.黄金長方形 さらに分割;

    

    float size = 150.0;

    float gWidth = size * 1.618;

    CGPoint start = CGPointMake(40, 50);

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:start];

    [path addLineToPoint:CGPointMake(start.x + gWidth, start.y)];

    [path addLineToPoint:CGPointMake(start.x + gWidth, start.y + size)];

    [path addLineToPoint:CGPointMake(start.x, start.y + size)];

    [path addLineToPoint:start];

    CAShapeLayer *sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor blackColor].CGColor;

    sl.lineWidth = 2;

    sl.path = path.CGPath;

    [self.view.layer addSublayer:sl];

    UIBezierPath *path2 = [UIBezierPath bezierPath];

    [path2 moveToPoint:CGPointMake(start.x + size, start.y)];

    [path2 addLineToPoint:CGPointMake(start.x + size, start.y + size)];

    

    float dh =  size – (size / 1.618);

    [path2 moveToPoint:CGPointMake(start.x + gWidth, start.y + dh)];

    [path2 addLineToPoint:CGPointMake(start.x + size, start.y + dh)];

    

    [path2 moveToPoint:CGPointMake(start.x + gWidth – dh, start.y)];

    [path2 addLineToPoint:CGPointMake(start.x + gWidth – dh, start.y + dh)];

    

    CAShapeLayer *sl2 = [[CAShapeLayer alloc] init];

    sl2.fillColor = [UIColor clearColor].CGColor;

    sl2.strokeColor = [UIColor blackColor].CGColor;

    sl2.lineWidth = 2;

    sl2.path = path2.CGPath;

    

    

    [shapes addObject:sl];

    [shapes addObject:sl2];

    

    [self drawShapesWithAnimation:sl2];

}

– (void)drawShapesWithAnimation:(CAShapeLayer*)sl

{

    [self.view.layer addSublayer:sl];

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@”strokeEnd”];

    pathAnimation.duration = 3.0;

    pathAnimation.fromValue = @(0.0f);

    pathAnimation.toValue = @(1.0f);

    [sl addAnimation:pathAnimation forKey:@”strokeEnd”];

}

– (void)clearShapes

{

    for (CAShapeLayer *sl in shapes) {

        [sl removeFromSuperlayer];

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end