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.

 
0
Kudos
 
0
Kudos

Now read this

Dipping Toe Further into Swift – Generics Edition

Work developments have prevented me from doing a lot of iOs, so as things are heating up with Swift and functional programming, my main involvement is reading. But I was reading [this post][macroPost] by Andrew Bancroft on using Swift... Continue →