3分でできるプログラミング
「指でクルクルする時計」です。

クルクルクロック

出来上がったら
 自分の作ったアプリで、こどもと一緒に「とけい」の勉強をしてみませんか。
道具
 Xcode (これ書いている時点で使っているのは、ver4.3です) 
材料
 QuartsCore.framework  ×1
 時計の針 ×2
 文字盤 ×1
とけいの針(短針と長針の二つ)を表示するためのClockHandという Object-Cクラスを作りましょう。
ヘッダファイルには、initWithFrame に針の長さと色を指定できるようにしたメソッドを ClockHand.h に追加します。
@interface ClockHand : UIView
-(id)initWithFrame:(CGRect)frame handLength:(float)length handColor:(UIColor*)color;
@end
実装していきます。ClockHand.m を開きましょう。
必要になる変数を用意します。@implementation ClockHand の上に次のコードを書きましょう。selected は気持ちよく針をクルクルさせるために、タッチイベントの発生と終了で設定する値です。
@interface ClockHand() {
    BOOL selected;              // 針がタップされていれば YES
    float handLength;           // 針の長さ
    CGPoint origin, handPoint;  // 時計の中心、針の先端
    UIColor *handColor;         // 針の色
}
@end
ヘッダに追加した init メソッドで、針の中心、長さ、色などを設定していきます。 @implementation ClockHand の下に、コードを書いていきましょう。時計の中心は、View の中心に設定しました。針の先端の初期位置は、y成分が0の3時方向としています。
-(id)initWithFrame:(CGRect)frame handLength:(float)length handColor:(UIColor*)color
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        handLength = length;
        handColor = color;
        origin = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0);
        handPoint.x = origin.x + handLength;
        handPoint.y = origin.y;
        selected = NO;
    }
    return self;
}
View の描画部分を書いていきます。中心から、そのときの針の先端まで線を引く処理を次のように。
– (void)drawRect:(CGRect)rect
{
    [handColor set];
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(ctx, 10.0);
    CGContextSetLineCap(ctx, kCGLineCapRound);
    CGContextMoveToPoint(ctx, origin.x, origin.y);
    CGContextAddLineToPoint(ctx, handPoint.x, handPoint.y);
    CGContextStrokePath(ctx);
}
タッチイベントの処理を書いていきます。長針、短針が重なるように View を配置するので、下になったView を選択できるように、hitTest の実装を行います。針の先、30×30 の領域をタッチした場合、そのViewのtouch イベントを拾うようにします。
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // 他の針がタッチで動くように、針の先端がタッチされたのでなければnil を返す。
    // ここを実装しないと、touch イベントが後ろに重ねた View に伝わらない。
    if (selected) {
        return self;
    }
    if (abs(point.x – handPoint.x) < 30 && abs(point.y – handPoint.y) < 30) {
        return self;
    }
    return nil;
}
指を離すまでは、タッチしたときに捕まえた針をまわすようにしたいので、touch の Begin, End, Cancel に selected に関する実装を行います。
– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    selected = YES;
}
– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    selected = NO;
}
– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    selected = NO;
}
針を実際に動かす処理を、touch moved に実装していきましょう。
– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *t = [touches anyObject];
    CGPoint tp = [t locationInView:self];
    
    // とけいの中心からの距離
    float rx = tp.x – origin.x;
    float ry = tp.y – origin.y;
    
    // 針の長さを調整
    float r = hypot(rx, ry); // r = root(x^2 + y^2)
    float rate = handLength / r;  
    handPoint.x = rx * rate + origin.x;
    handPoint.y = ry * rate + origin.y;
    
    [self setNeedsDisplay];
}
以上で、針の実装は完了です。 
ViewController に組み込んでいきましょう。ViewController には次の二つのインポートが必要になります。(QuartzCore は追加ライブラリなので、Target – BuildPhases – Link Binary With Libraries に追加しておく必要があります。)
#import <QuartzCore/QuartzCore.h>
#import “ClockHand.h”
インポートしたら、viewDidLoad に実装を追加していきましょう。時計版の作成と短針、長針の作成を書いていきます。
– (void)viewDidLoad
{
    [super viewDidLoad];
    
    // とけい盤
    float r = 125.0;
    UIView *board = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2 * r, 2 * r)];
    board.center = self.view.center;
    board.backgroundColor = [UIColor whiteColor];
    board.layer.cornerRadius = 125;
    board.layer.borderWidth = 5;
    board.layer.borderColor = [[UIColor darkGrayColo
r] CGColor];
    for (int i=0; i<12; i++) {
        UIView *hour = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
        hour.backgroundColor = [UIColor darkGrayColor];
        hour.layer.cornerRadius = 4;
        float rx = r + 0.9 * r * cos(2 * M_PI * i * (1.0/12.0));
        float ry = r + 0.9 * r * sin(2 * M_PI * i * (1.0/12.0));
        hour.center = CGPointMake(rx, ry);
        [board addSubview:hour];
    }
    [self.view addSubview:board];
    
    
    // とけいの短針
    ClockHand *shortHand = [[ClockHand alloc] initWithFrame:board.frame handLength:60 handColor:[UIColor redColor]];
    [self.view addSubview:shortHand];
    
    
    // とけいの長針
    ClockHand *longHand = [[ClockHand alloc] initWithFrame:board.frame handLength:110 handColor:[UIColor greenColor]];
    [self.view addSubview:longHand];
    
}
以上で完了です。
ぜひ、お試しください。
JUGEMテーマ:iphone


 ソース

ClockHand.h

#import <UIKit/UIKit.h>

@interface ClockHand : UIView

-(id)initWithFrame:(CGRect)frame handLength:(float)length handColor:(UIColor*)color;

@end

CloclHand.m

#import “ClockHand.h”

@interface ClockHand() {

    BOOL selected;              // 針がタップされていれば YES

    float handLength;           // 針の長さ

    CGPoint origin, handPoint;  // 時計の中心、針の先端

    UIColor *handColor;         // 針の色

}

@end

@implementation ClockHand

-(id)initWithFrame:(CGRect)frame handLength:(float)length handColor:(UIColor*)color

{

    self = [super initWithFrame:frame];

    if (self) {

        self.backgroundColor = [UIColor clearColor];

        handLength = length;

        handColor = color;

        origin = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0);

        handPoint.x = origin.x + handLength;

        handPoint.y = origin.y;

        selected = NO;

    }

    return self;

}

– (void)drawRect:(CGRect)rect

{

    [handColor set];

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextSetLineWidth(ctx, 10.0);

    CGContextSetLineCap(ctx, kCGLineCapRound);

    CGContextMoveToPoint(ctx, origin.x, origin.y);

    CGContextAddLineToPoint(ctx, handPoint.x, handPoint.y);

    CGContextStrokePath(ctx);

}

#pragma mark – touch controll

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    selected = YES;

}

– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

{

    selected = NO;

}

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

    selected = NO;

}

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    UITouch *t = [touches anyObject];

    CGPoint tp = [t locationInView:self];

    

    // とけいの中心からの距離

    float rx = tp.xorigin.x;

    float ry = tp.yorigin.y;

    

    // 針の長さを調整

    float r = hypot(rx, ry); // r = root(x^2 + y^2)

    float rate = handLength / r;  

    handPoint.x = rx * rate + origin.x;

    handPoint.y = ry * rate + origin.y;

    

    [self setNeedsDisplay];

}

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

{

    // 他の針がタッチで動くように、針の先端がタッチされたのでなければnil を返す。

    // ここを実装しないと、touch イベントが後ろに重ねた View に伝わらない。

    if (selected) {

        return self;

    }

    if (abs(point.xhandPoint.x) < 30 && abs(point.yhandPoint.y) < 30) {

        return self;

    }

    return nil;

}

@end

ViewController.m

#import <QuartzCore/QuartzCore.h>

#import “ViewController.h”

#import “ClockHand.h”

@interface ViewController ()

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    // とけい盤

    float r = 125.0;

    UIView *board = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2 * r, 2 * r)];

    board.center = self.view.center;

    board.backgroundColor = [UIColor whiteColor];

    board.layer.cornerRadius = 125;

    board.layer.borderWidth = 5;

    board.layer.borderColor = [[UIColor darkGrayColor] CGColor];

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

        UIView *hour = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];

        hour.backgroundColor = [UIColor darkGrayColor];

        hour.layer.cornerRadius = 4;

        float rx = r + 0.9 * r * cos(2 * M_PI * i * (1.0/12.0));

        float ry = r + 0.9 * r * sin(2 * M_PI * i * (1.0/12.0));

        hour.center = CGPointMake(rx, ry);

        [board addSubview:hour];

    }

    [self.view addSubview:board];

    

    

    // とけいの短針

    ClockHand *shortHand = [[ClockHand alloc] initWithFrame:board.frame handLength:60 handColor:[UIColor redColor]];

    [self.view addSubview:shortHand];

    

    

    // とけいの長針

    ClockHand *longHand = [[ClockHand alloc] initWithFrame:board.frame handLength:110 handColor:[UIColor greenColor]];

    [self.view addSubview:longHand];

    

}

– (void)viewDidUnload

{

    [super viewDidUnload];

    // Release any retained subviews of the main view.

}

– (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

}

@end