キッチンタイマーの作り方をメモ

(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 borderrasterize

        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.xlevel.center.x;

        float y = tPoint.ylevel.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