user5709700
user5709700

Reputation:

ios 9.2 predictedTouchesForTouch: No documentation

WWDC 2015 - Session 233 - iOS: https://developer.apple.com/videos/play/wwdc2015/233/?time=74

I can find Apple demo code, but for the life of me can't find any actual documentation on [UIEvent predictedTouchesForTouch:].

It was supposed to be an iOS 9 API. Is this API active and just not documented yet? I can see the API diff that they added it to Swift, yet still no documentation.

Upvotes: 1

Views: 335

Answers (1)

Rob
Rob

Reputation: 438047

Yes, the documentation for predicted touches (much like the documentation for coalesced touches) is meager. At this point (Xcode 7.2 and 7.3 Beta 4), the only reference I see (outside the WWDC video you reference and other demonstrations scattered about the web) is in the header, which describes the predicted touches as so:

An array of auxiliary UITouch’s for touch events that are predicted to occur for a given main touch. These predictions may not exactly match the real behavior of the touch as it moves, so they should be interpreted as an estimate.

But it works precisely as described in the WWDC video you reference, both Swift and Objective-C.

Note, you might not see predicted and coalesced touches on the simulator, but you will if you use a capable device. I see the occasional predicted touch when using my iPhone 6+, but see them consistently on iPad Pro (and even more if you use an Apple Pencil on iPad Pro).

Just to illustrate coalesced and predicted touches, here is an Objective-C demonstration:

@interface ViewController ()

@property (nonatomic, strong) UIBezierPath *path;
@property (nonatomic, weak) CAShapeLayer *pathLayer;
@property (nonatomic, weak) CAShapeLayer *predictedPathLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // set up layer for the main (non-predicted) path; line blue line

    CAShapeLayer *mainPathLayer = [CAShapeLayer layer];
    mainPathLayer.lineWidth = 1;
    mainPathLayer.strokeColor = [UIColor blueColor].CGColor;
    mainPathLayer.fillColor = [UIColor clearColor].CGColor;
    mainPathLayer.lineCap = kCALineCapRound;
    mainPathLayer.lineJoin = kCALineJoinRound;
    mainPathLayer.frame = self.view.layer.bounds;
    [self.view.layer addSublayer:mainPathLayer];
    self.pathLayer = mainPathLayer;

    // set up layer for the predicted path, if any; thicker red line (just so I can see it clearly)

    CAShapeLayer *predictedPathLayer = [CAShapeLayer layer];
    predictedPathLayer.lineWidth = 5;
    predictedPathLayer.strokeColor = [UIColor redColor].CGColor;
    predictedPathLayer.fillColor = [UIColor clearColor].CGColor;
    predictedPathLayer.lineCap = kCALineCapRound;
    predictedPathLayer.lineJoin = kCALineJoinRound;
    predictedPathLayer.frame = self.view.layer.bounds;
    [self.view.layer addSublayer:predictedPathLayer];
    self.predictedPathLayer = predictedPathLayer;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    self.path = [UIBezierPath bezierPath];
    [self.path moveToPoint:[touch locationInView:self.view]];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self.view];

    // handle coalesced touches

    NSArray<UITouch *> *coalescedTouches = [event coalescedTouchesForTouch:touch];
    for (UITouch *coalescedTouch in coalescedTouches) {
        location = [coalescedTouch locationInView:self.view];
        [self.path addLineToPoint:location];
    }

    self.pathLayer.path = self.path.CGPath;

    // now handle predicted touches

    UIBezierPath *predictedPath = [UIBezierPath bezierPath];
    [predictedPath moveToPoint:location];
    NSArray<UITouch *> *predictedTouches = [event predictedTouchesForTouch:touch];


    for (UITouch *predictedTouch in predictedTouches) {
        [predictedPath addLineToPoint:[predictedTouch locationInView:self.view]];
    }

    self.predictedPathLayer.path = predictedPath.CGPath;

    // for diagnostic purposes, let's log the count of each; do not do this in production app

    NSLog(@"%ld %ld", [coalescedTouches count], [predictedTouches count]);
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.predictedPathLayer.path = NULL; // discard any predicted path, because that's no longer valid
}

@end

If you need to support iOS versions before 9, you'll want to check respondsToSelector, too.

The Swift example is very similar. See this unrelated post about smooth curves, which illustrates how to use predicted (and coalesced) touches in Swift: Drawing class drawing straight lines instead of curved lines

Upvotes: 2

Related Questions