Last active
December 22, 2015 19:19
-
-
Save janodev/6519204 to your computer and use it in GitHub Desktop.
ARSketchView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@interface ARSketchView : UIView | |
- (IBAction) clear; | |
- (IBAction) replay; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment