Upgrade to Pro — share decks privately, control downloads, hide ads and more …

To drawRect or not to drawRect (MobOS 2015)

Ddd6d3bac7772fa67fc5e312a18bdaec?s=47 sammyd
February 19, 2015

To drawRect or not to drawRect (MobOS 2015)

A review of the different options for drawing graphics on iOS, including UIKit, Core Graphics and Core Animation.
This is the version presented at Romanian MobOS Con 2nd edition.

Ddd6d3bac7772fa67fc5e312a18bdaec?s=128

sammyd

February 19, 2015
Tweet

More Decks by sammyd

Other Decks in Programming

Transcript

  1. to drawRect or not to drawRect? http://is.gd/drawRect

  2. @iwantmyrealname Sam Davies

  3. shinobicontrols.com/ios8

  4. @shinobicontrols

  5. shinobicontrols

  6. what do i mean by drawing?

  7. Drawing Checklist Shapes Gradients Text Lorem Textures Animation

  8. how do i draw on iOS?

  9. Drawing on iOS UIKit CoreGraphics CoreAnimation OpenGLES

  10. How do the bits fit together? UIView Hierarchy Graphics Hardware

    via CALayer rotate 30° opacity 60% backed by drawRect:
  11. So what actually is drawRect? ★ UIView backed by CALayer

    ★ Implementation of CALayerDelegate method drawLayer:inContext: ★ Informal protocol ★ Use to provide layer content and arrange sublayers
  12. I want to draw some

  13. simplistic approach with UIImageView additional configurability with CoreGraphics efficient animation

    with CoreAnimation
  14. SCArrowView protocol @protocol SCArrowView <NSObject>
 
 - (instancetype)initWithFrame:(CGRect)frame
 from:(CGPoint)from
 to:(CGPoint)to;

    @property (nonatomic, assign) CGPoint from;
 @property (nonatomic, assign) CGPoint to;
 @property (nonatomic, assign) CGFloat headSize;
 @property (nonatomic, assign) CGFloat lineThickness;
 @property (nonatomic, assign) CGFloat bendiness;
 @property (nonatomic, strong) UIColor *color; - (void)redrawArrow; @end
  15. UIImageView

  16. ★UIView = blank canvas ★Various subclasses for creating content ★UIImageView

    displays images ★Highly optimised for this purpose UIImageView
  17. UIImageView Arrow if(! self.imageView && self.image) {
 self.imageView = [[UIImageView

    alloc] initWithImage:self.image];
 [self addSubView:self.imageView];
 } from to
  18. UIImageView Arrow CGPoint ivCentre = CGPointZero;
 ivCentre.x = (self.from.x +

    self.to.x) / 2.0;
 ivCentre.y = (self.from.y + self.to.y) / 2.0;
 self.imageView.center = ivCentre; from to
  19. UIImageView Arrow CGFloat arrowLength = sqrt(pow((self.to.y - self.from.y),2) +
 pow((self.to.x

    - self.from.x),2) );
 CGRect arrowBounds = self.imageView.bounds;
 arrowBounds.size.width = arrowLength;
 self.imageView.bounds = arrowBounds; from to
  20. UIImageView Arrow CGFloat arrowLength = sqrt(pow((self.to.y - self.from.y),2) +
 pow((self.to.x

    - self.from.x),2) );
 CGRect arrowBounds = self.imageView.bounds;
 arrowBounds.size.width = arrowLength;
 self.imageView.bounds = arrowBounds; from to
  21. UIImageView Arrow from to CGFloat arrowAngle = atan2((self.to.y - self.from.y),


    (self.to.x - self.from.x));
 self.arrowImageView.transform =
 CGAffineTransformMakeRotation(arrowAngle);
  22. UIImageView Arrow from to UIImage *preColoredArrow = [self preColoredArrowImage];
 self.tintColor

    = self.color;
 self.image = [preColoredArrow
 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
 self.arrowImageView.image = self.image;
  23. demonstration

  24. UIImageView Arrow

  25. UIImageView Arrow

  26. UIImageView Arrow

  27. Drawing Checklist Shapes Gradients Text Lorem Textures Animation

  28. CoreGraphics

  29. CoreGraphics

  30. CGContextAddLineToPoint CGContextAddArc
 CGContextAddArcToPoint CGContextAddCurve
 CGContextAddQuadCurve Paths

  31. - addLineToPoint: + bezierPathWithOvalInRect:
 - addArcWithCenter:radius:startAngle:
 endAngle:
 clockwise: - addCurveToPoint:controlPoint1:


    controlPoint2:
 - addQuadCurveToPoint:controlPoint: UIBezierPath
  32. CoreGraphics Functionality Patterns Shadows Gradients Masks

  33. drawRect ★Presets the CGContext for you ★UIGraphicsGetCurrentContext() ★Paint over the

    top of the pre-rendered view
  34. CoreGraphics Arrow CGContextMoveToPoint(cxt, start.x, start.y); CGContextAddQuadCurveToPoint(cxt, control.x, control.y, end.x, end.y);

    CGContextMoveToPoint(cxt, arrowSide1.x, arrowSide1.y); CGContextAddLineToPoint(cxt, arrowSide2.x, arrowSide2.y); CGContextAddLineToPoint(cxt, end.x, end.y); CGContextStrokePath(cxt); CGContextRef cxt = UIGraphicsGetCurrentContext();
  35. demonstration

  36. Adding animation - (void)animationUpdate:(CADisplayLink *)sender
 {
 self.animating = YES
 if(!self.timer)

    {
 self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(animationUpdate:)];
 [self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
 self.animationStartTime = CACurrentMediaTime();
 } 
 CGFloat propComplete = (CACurrentMediaTime() - self.animationStartTime) / self.animationTime;
 if(propComplete >= 1) {
 self.currentEnd = self.to;
 [self.timer invalidate];
 self.timer = nil;
 } else {
 self.currentEnd = CGPointMake((self.to.x - self.from.x) * propComplete + self.from.x,
 (self.to.y - self.from.y) * propComplete + self.from.y);
 } 
 [self setNeedsDisplay];
 }
  37. demonstration

  38. Drawing Checklist Shapes Gradients Text Lorem Textures Animation

  39. CoreAnimation

  40. Presentation Tree Render Tree Application Framework ★ CALayer is the

    fundamental object ★ Exists in a hierarchy ★ 3 distinct hierarchies Model Tree CoreAnimation
  41. CALayer self.view.layer.cornerRadius = 5.0; self.view.layer.borderColor = [UIColor grayColor].CGColor; self.view.layer.borderWidth =

    2; We’ve all used CALayer before… …usually to make this… into this…
  42. Providing Content to CALayer ★ contents property ★ drawLayer:inContext: method

    on CALayerDelegate ★ Subclass and override drawing methods - drawInContext: or display ★ Specialist subclasses of CALayer
  43. CALayer Subclasses Shape Gradient EAGL Replicator Scroll Text Tiled …

    Lorem
  44. Construction of CAArrow 2 CAShapeLayers UIView:layer (CALayer)

  45. Creating Arrow Path self.arrowPathLayer = [CAShapeLayer layer];
 [self.layer addSublayer:self.arrowPathLayer]; self.arrowPathLayer.bounds

    = self.bounds;
 self.arrowPathLayer.position = CGPointMake(CGRectGetMidX(self.bounds),
 CGRectGetMidY(self.bounds)); self.arrowPathLayer.strokeColor = self.color.CGColor;
 self.arrowPathLayer.lineWidth = self.lineThickness; UIBezierPath *path = [self.arrowPath arrowBezierPath];
 self.arrowPathLayer.path = path.CGPath;
  46. Creating Arrow Head self.arrowHeadLayer = [CAShapeLayer layer];
 [self.layer addSublayer:self.arrowHeadLayer]; self.arrowHeadLayer.bounds

    = self.bounds;
 self.arrowHeadLayer.position = CGPointMake(CGRectGetMidX(self.bounds),
 CGRectGetMidY(self.bounds)); self.arrowHeadLayer.strokeColor = self.color.CGColor;
 self.arrowHeadLayer.lineWidth = self.lineThickness; UIBezierPath *headPath = [self arrowHeadBezierPath]; self.arrowHeadLayer.path = headPath.CGPath;
  47. demonstration

  48. CAAnimation CALayer Implicit backgroundColor borderColor borderWidth bounds cornerRadius mask opacity

    position transform … CAGradientLayer colors locations startPoint endPoint CAShapeLayer lineDashPhase fillColor path* strokeStart strokeEnd … CATextLayer fontSize* foregroundColor* CAReplicatorLayer instanceAlphaOffset instanceColor instanceDelay … CAShapeLayer lineDashPhase fillColor path* strokeStart
 strokeEnd
 …
  49. Stroke Animation 0 1 CABasicAnimation *animation = [CABasicAnimation
 animationWithKeyPath:@"strokeEnd"];
 animation.duration

    = 2;
 animation.fromValue = @0;
 animation.toValue = @1;
 animation.timingFunction = [CAMediaTimingFunction
 functionWithName:kCAMediaTimingFunctionEaseIn];
  50. Arrow Head Animation CABasicAnimation *headAnimationLeft = [CABasicAnimation
 animationWithKeyPath:@"strokeEnd"];
 headAnimationLeft.duration =

    1.0;
 headAnimationLeft.fromValue = @0.5;
 headAnimationLeft.toValue = @1;
 headAnimationLeft.beginTime = 2;
 headAnimationLeft.timingFunction = [CAMediaTimingFunction
 functionWithName:kCAMediaTimingFunctionEaseOut]; CABasicAnimation *headAnimationRight = [CABasicAnimation
 animationWithKeyPath:@"strokeStart"];
 headAnimationRight.duration = 1.0;
 headAnimationRight.fromValue = @0.5;
 headAnimationRight.toValue = @0;
 headAnimationRight.beginTime = 2;
 headAnimationRight.timingFunction = [CAMediaTimingFunction
 functionWithName:kCAMediaTimingFunctionEaseOut]; 1 0.5 0 1 0.5 0
  51. Arrow Head Animation CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
 animationGroup.duration =

    3;
 animationGroup.animations = @[headHidden, headAnimationRight,
 headAnimationLeft]; [self.arrowPathLayer addAnimation:animation
 forKey:@"SCArrowDrawAnimation"];
 [self.arrowHeadLayer addAnimation:animationGroup
 forKey:@"SCArrowDrawHeadAnimation"];
  52. demonstration

  53. Drawing Checklist Shapes Gradients Text Lorem Textures Animation

  54. Animation

  55. Performance CoreAnimation CoreGraphics

  56. Performance CoreGraphics CoreAnimation UIImageView cpu time fps ❌ ❌

  57. ★ UIImageView is mega simple ★ Use UIBezierPath to draw

    shapes ★ Don’t try and animate with drawRect ★ Discover the CALayer subclasses ★ CALayer offers software design advantages ★ CALayer when interaction not required in summary
  58. learn by building thanks is.gd/drawRect github.com/sammyd/iOS-ArrowDrawing shinobicontrols.com/ios8 @iwantmyrealname