はじめに
WatchKitについて、WatchKit Programming GuideやWatchKit Human Interface Guidelinesを見て、シンプルに作れるなという印象と、あまり色々やれなそうだなっていうのが感想でした。
ただその中で、アニメーションはあるけどパラパラ漫画だし、Appleが公式で作ってるようなアナログ時計ってどうやって表示したら良いの、という疑問が合ったので、色々試した結果できました。
実装(Objective-c)
既に動かすところまでの記事が投稿されてたりするので、下記の参考にプロジェクトを作って下さい。動いた所から記述します。
1分でつくれるAppleWatch対応アプリ & WatchKit 全API解説
WatchKit Catalog(サンプルコード)を起動する方法
では実装です。
Interface.storyboardでMainのInterfaceにImageを貼り付けます、スクショを貼り付けられないので申し訳ないのですが、Interface.storyboardを開いて、Mainの矢印が書いてあるInterface ControllerにImageを貼り付けて下さい。
貼り付けたImageを選択した状態で、attribute inspectorを開いて下さい、Sizeという項目があるのでWidthもHeightもSize to Fit Contentから、Relative to Containerにして下さい。
そして貼り付けたImageをInterfaceController.mで参照できるようにOutletを設定して下さい。
1 2 3 4 5 6 7 8 |
#import "InterfaceController.h" @interface InterfaceController() @property (weak, nonatomic) IBOutlet WKInterfaceImage *image; // これ @end @implementation InterfaceController |
ここまででStoryboardの設定はおしまいです。
続きまして、一秒毎に表示を更新するため、NSTimerを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#import "InterfaceController.h" @interface InterfaceController() { NSTimer *__timer; } @property (weak, nonatomic) IBOutlet WKInterfaceImage *image; @end @implementation InterfaceController - (instancetype)initWithContext:(id)context { self = [super initWithContext:context]; if (self){ // Initialize variables here. // Configure interface objects here. NSLog(@"%@ initWithContext", self); } return self; } - (void)willActivate { // This method is called when watch view controller is about to be visible to user NSLog(@"%@ will activate", self); __timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(tick:) userInfo:nil repeats:YES]; } - (void)didDeactivate { // This method is called when watch view controller is no longer visible NSLog(@"%@ did deactivate", self); if ([__timer isValid]) { [__timer invalidate]; } } @end |
これで後は描画だけです、tickメソッドが1秒毎に呼ばれるので、そこで描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
- (void)tick:(NSTimer*)timer { // スクリーンサイズ取得 CGSize screenSize = [[WKInterfaceDevice currentDevice] screenBounds].size; float cx = screenSize.width / 2.0f; float cy = screenSize.height / 2.0f; float mRad = -90.0f * M_PI / 180.0f; // ベースの針の長さ float baseR = screenSize.width / 2.0f; // 時刻を取得 NSDate *date = [NSDate date]; NSCalendar *calendar = [NSCalendar currentCalendar]; NSDateComponents *dateComps = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:date]; // 描画 UIGraphicsBeginImageContextWithOptions(CGSizeMake(screenSize.width, screenSize.height), NO, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context, 255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f, 1.0f); // 秒針 float rad = 2.0f * M_PI * dateComps.second / 60.0f + mRad; float sr = baseR; // 針の長さ float tx = cx + sr * cos(rad); float ty = cy + sr * sin(rad); CGContextSetLineWidth(context, 1.5f); CGContextMoveToPoint(context, cx, cy); CGContextAddLineToPoint(context, tx, ty); CGContextStrokePath(context); // 分針 rad = 2.0f * M_PI * dateComps.minute / 60.0f + mRad; sr = baseR; tx = cx + sr * cos(rad); ty = cy + sr * sin(rad); CGContextStrokePath(context); CGContextSetLineWidth(context, 3.0f); CGContextMoveToPoint(context, cx, cy); CGContextAddLineToPoint(context, tx, ty); CGContextStrokePath(context); // 時針 rad = 2.0f * M_PI * dateComps.hour / 12.0f + mRad; sr = baseR * 0.6f; tx = cx + sr * cos(rad); ty = cy + sr * sin(rad); CGContextStrokePath(context); CGContextSetLineWidth(context, 5.0f); CGContextMoveToPoint(context, cx, cy); CGContextAddLineToPoint(context, tx, ty); CGContextStrokePath(context); // 色々描画したのをUIImageに変換 UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // 画像をセットする [_image setImage:img]; } |
これで完成です!
実行するとアナログ時計が表示されます。
スクリーンショットが無いと寂しすぎますが、CoreGraphicsでUIImage作ってImageにset出来るなら、表示面ではなんとかなるかなと思います。
追伸:さすがに寂しいので、現行XCodeで、同じコード実装してスクショ取りました。下記のような時計が表示されて、一秒ごとに針が動きます。
更に追伸:まだ実機デバックができたわけではないので、もしかしたら大丈夫かもしれませんが、 今回のように画像を動的に作る場合、時針、分針、秒針は別々のImageに描画したり、頻繁に動く秒針はキャッシュしておかないと電池消費が激しくなったりするかもです。画像のキャッシュに関しては下記の記事に書きましたので、よろしかったらどうぞ。