キッチンタイマーの作り方をメモ
(XcodeのIOS6 Simulatorで試しています。)
ポイント
・atanを使ってタッチした座標から角度を算出する
・UIViewのAddArcを使って円グラフの要領でメモリを表現
サンプルコード
CircleGraph.h
@interface CircleGraph : UIView
– (void)setLevel:(int)level total:(int)total;
@end
CircleGraph.m
#import “CircleGraph.h”
@interface CircleGraph() {
float _total;
float _level;
}
@end
@implementation CircleGraph
– (void)setLevel:(int)level total:(int)total
{
_level = level;
_total = total;
[self setNeedsDisplay];
}
– (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor redColor] set];
float angle = 2 * M_PI * (_level / _total) – M_PI_2;
CGPoint o = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.width * 0.5);
CGContextMoveToPoint(context, o.x, o.y);
CGContextAddArc(context, o.x, o.x, o.y, –M_PI_2, angle, NO);
CGContextFillPath(context);
}
@end
ViewController.m
#import “ViewController.h”
#import “CircleGraph.h”
#import <QuartzCore/QuartzCore.h>
#import <AVFoundation/AVFoundation.h>
@interface ViewController () {
CircleGraph *level;
UILabel *startLabel;
float time;
BOOL start;
CADisplayLink *timer;
AVAudioPlayer *player;
}
@end
@implementation ViewController
– (void)viewDidLoad
{
[super viewDidLoad];
// タイマー盤の数値を色で表示
level = [[CircleGraph alloc] initWithFrame:CGRectMake(0, 0, 260, 260)];
level.backgroundColor = [UIColor whiteColor];
level.center = self.view.center;
[self.view addSubview:level];
// メモリ付きの文字盤を作成
[self createTopPlate];
// 中央に丸を表示
UIView *centerCircle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
centerCircle.layer.cornerRadius = 30.0;
centerCircle.center = self.view.center;
centerCircle.backgroundColor = [UIColor whiteColor];
[self.view addSubview:centerCircle];
// ラベル
startLabel = [[UILabel alloc] init];
startLabel.font = [UIFont boldSystemFontOfSize:30];
startLabel.text = @” Start “;
[startLabel sizeToFit];
startLabel.center = CGPointMake(50, 50);
startLabel.textColor = [UIColor grayColor];
[centerCircle addSubview:startLabel];
// タッチでタイマースタート
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
[centerCircle addGestureRecognizer:tap];
// 状態の初期化
start = NO;
}
– (void)createTopPlate
{
// 一番上の板にはメモリを刻む
UIView *plate1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
plate1.center = self.view.center;
plate1.backgroundColor = [UIColor clearColor];
[self.view addSubview:plate1];
// メモリを刻む
for (int i=0; i<60; i++) {
CALayer *line = [[CALayer alloc] init];
line.frame = CGRectMake(0, 0, 15.0, 2.0);
line.backgroundColor = [UIColor lightGrayColor].CGColor;
float th = M_PI / 30.0;
float x = (250.0 / 2.0) * cos(th * i) + 150;
float y = (250.0 / 2.0) * sin(th * i) + 150;
line.position = CGPointMake(x,y);
// メモリの角度を調整する
float angle = th * i;
line.transform = CATransform3DMakeRotation(angle, 0, 0, 1.0);
// ギザギザ対策にclear borderとrasterize
line.borderWidth = 3;
line.borderColor = [UIColor clearColor].CGColor;
line.shouldRasterize = YES;
[plate1.layer addSublayer:line];
}
// 5 毎に文字盤を刻む
for (int i=0; i<60; i+=5) {
UILabel *number = [[UILabel alloc] init];
number.text = [NSString stringWithFormat:@”%d”,i];
number.textAlignment = 0; // center
number.backgroundColor = [UIColor clearColor];
[number sizeToFit];
// 文字盤の位置
float th = (M_PI / 30.0) * i – M_PI_2; // 0を真上に持ってくる
float x = (290.0 / 2.0) * cos(th) + 150;
float y = (290.0 / 2.0) * sin(th) + 150;
number.center = CGPointMake(x, y);
[plate1 addSubview:number];
}
}
– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!start) {
UITouch *t = [touches anyObject];
CGPoint tPoint = [t locationInView:self.view];
// タッチした位置から、適当にメモリを動かす
float x = tPoint.x – level.center.x;
float y = tPoint.y – level.center.y;
float angle = atan2(y, x);
time = ((angle + M_PI_2) / (2.0 * M_PI)) * 600.0;
[level setLevel:time total:600];
}
if (time == 0) {
startLabel.textColor = [UIColor lightGrayColor];
} else {
startLabel.textColor = [UIColor blackColor];
}
}
– (void)tap
{
if (!start) {
start = YES;
[self startTimer];
}
}
– (void)startTimer
{
timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
– (void)tick:(CADisplayLink*)sender
{
time -= sender.duration * 10;
if (time > 0) {
[level setLevel:time total:600];
startLabel.text = [NSString stringWithFormat:@”%d.%d”, (int)time / 10, (int)(time * 10) % 100];
} else {
// 終了。
time = 0;
[level setLevel:0 total:600];
[timer invalidate];
// 色を変える
startLabel.text = @” Start “;
startLabel.textColor = [UIColor lightGrayColor];
// 状態を戻す
start = NO;
// AudioServicesでアラームでもならしたり
[self playAlarm];
}
}
– (void)playAlarm
{
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:@”alarm” withExtension:@”mp3″];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[player play];
}
– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
@end