Apple Watch Crown Events – Thinking About Discretely Triggered Events
One of the biggest frustration points for me on Apple Watch when working out is that a wet screen does not recognize touches very well. So a workout app that lets me mark a lap, pause the workout, or anything like that is limited, because many times it fails because I sweat a lot [1].
But now, with Apple exposing WKCrownSequencer
and its delegate means that apps can receive direct input from the crown. Examples shown include rolling the crown and moving a marker along a plot.
But how does this help for discrete events? It is fairly trivial to create discrete events by triggering something based on a threshold rotationalDelta
. Below is the code (not Swift, sorry!) for a quick proof of concept for marking laps by quickly spinning up, and stopping the timer by quickly spinning down.
I’ve only tested on my simulator so far, but when I test on the watch, I’ll try to capture video.
I would kill for a workout app that does this.
#import "InterfaceController.h"
@interface InterfaceController()<WKCrownDelegate>
@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceLabel *label;
@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceLabel *resultLabel;
@property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceTimer *timer;
@property (nonatomic) NSNumber *previousDelta;
@property (nonatomic) NSDate *startDate;
@end
@implementation InterfaceController
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
[self.label setText:@"--"];
[self.resultLabel setText:@"--"];
self.crownSequencer.delegate= self;
}
- (void)crownDidBecomeIdle:(WKCrownSequencer *)crownSequencer
{
self.previousDelta = nil;
}
- (void)crownDidRotate:(WKCrownSequencer *)crownSequencer rotationalDelta:(double)rotationalDelta
{
[self.label setText:[NSString stringWithFormat:@"delta: %.2f", fabs(rotationalDelta)]];
if (self.previousDelta && self.previousDelta.floatValue == 0) {
if (rotationalDelta > 0.5) {
[self discreteEventUp];
} else if (rotationalDelta < -0.5) {
[self discreteEventDown];
}
} else if (!self.previousDelta){
self.label.textColor = [UIColor whiteColor];
}
self.previousDelta = @(rotationalDelta);
}
- (void)discreteEventUp
{
self.label.textColor = [UIColor redColor];
[self.resultLabel setText:[NSString stringWithFormat:@"Lap: %.2f sec.", [[NSDate date] timeIntervalSinceDate:self.startDate]]];
self.startDate = [NSDate date];
[self.timer start];
}
- (void)discreteEventDown
{
self.label.textColor = [UIColor redColor];
[self.resultLabel setText:@"Timer Stopped"];
[self.timer stop];
}
- (void)didAppear {
[self.crownSequencer focus];
[self.timer start];
self.startDate = [NSDate date];
}
@end
[1]: Ewww, I know.