public
Last active

ARSketchView

  • Download Gist
ARSketchView.h
Objective-C
1 2 3 4 5 6
@interface ARSketchView : UIView
- (IBAction) clear;
- (IBAction) replay;
@end
ARSketchView.m
Objective-C
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
 
#import "ARSketchView.h"
#import <QuartzCore/QuartzCore.h>
 
 
@interface ARBezierPath : UIBezierPath
@property (nonatomic,assign) NSTimeInterval timelapse;
@end
 
@implementation ARBezierPath
@end
 
 
@implementation ARSketchView
{
NSMutableArray *_finishedPaths;
NSMutableDictionary *_ongoingPath;
}
 
 
-(void) awakeFromNib {
[self setup];
}
 
 
-(void) setup {
_ongoingPath = [NSMutableDictionary dictionary];
_finishedPaths = [NSMutableArray array];
}
 
 
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self){
[self setup];
}
return self;
}
 
 
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
ARBezierPath *path = [ARBezierPath new];
CGPoint point = [touch locationInView:self];
[path moveToPoint:point];
path.timelapse = [NSDate timeIntervalSinceReferenceDate];
 
_ongoingPath[@((int)touch)] = path;
}
}
 
 
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
NSNumber *key = @((int)touch);
ARBezierPath *path = _ongoingPath[key];
if (path){
CGPoint point = [touch locationInView:self];
[path addLineToPoint:point];
}
}
// repaint to show the new line added
[self setNeedsDisplay];
}
 
 
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
NSNumber *key = @((int)touch);
ARBezierPath *path = _ongoingPath[key];
if (path){
CGPoint point = [touch locationInView:self];
[path addLineToPoint:point];
path.timelapse = [NSDate timeIntervalSinceReferenceDate] - path.timelapse;
}
[_ongoingPath removeObjectForKey:key];
[_finishedPaths addObject:path];
}
[self setNeedsDisplay];
}
 
 
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
 
 
- (void) drawRect:(CGRect)rect
{
[super drawRect:rect];
 
for (ARBezierPath *path in _finishedPaths){
[path stroke];
}
for (ARBezierPath *path in [_ongoingPath allValues]){
[path stroke];
}
}
 
 
#pragma mark -
 
 
- (IBAction) clear
{
[CATransaction begin];
_finishedPaths = [NSMutableArray array];
_ongoingPath = [NSMutableDictionary dictionary];
for (CALayer *layer in self.layer.sublayers){
[layer removeFromSuperlayer];
}
[CATransaction commit];
[self setNeedsDisplay];
}
 
 
- (IBAction) replay
{
UIView *preview = [[UIView alloc] initWithFrame:self.frame];
preview.backgroundColor = [UIColor whiteColor];
[self addSubview:preview];
NSTimeInterval total = 0.0;
for (ARBezierPath *path in _finishedPaths)
{
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blackColor] CGColor];
shapeLayer.fillColor = nil;
shapeLayer.lineWidth = 1.0f;
shapeLayer.lineJoin = kCALineJoinBevel;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = path.timelapse;
pathAnimation.fromValue = @(0.0f);
pathAnimation.toValue = @(1.0f);
 
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, total * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[shapeLayer addAnimation:pathAnimation forKey:@"strokeEnd"];
[preview.layer addSublayer:shapeLayer];
});
total += path.timelapse;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, total * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[preview removeFromSuperview];
});
 
}
 
 
@end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.