黄金長方形の作図法をアニメーションで表示する電子テキストのような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