Frage

I know how to draw a rectangle outline to the screen with something like this:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGPathRef path = CGPathCreateWithRect(rect, NULL);
    [[UIColor greenColor] setStroke];
    CGContextAddPath(context, path);
    CGContextDrawPath(context, kCGPathFillStroke);
    CGPathRelease(path);
}

But what I want is to have the "pen" start at the top center of the rectangle and draw around the edges at some variable speed, so that you can actually see the rectangle getting drawn as the "pen" moves. Is this possible? How?

War es hilfreich?

Lösung

You could easily use a CALayerShape with a Pen Image and do it like this (I added a button to the view which triggered the drawing):

#import "ViewController.h"

@interface ViewController () {
    UIBezierPath *_drawPath;
    CALayer      *_pen;
    UIBezierPath *_penPath;
    CAShapeLayer *_rectLayer;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIImage *penImage = [UIImage imageNamed:@"pen"];

    _drawPath = [UIBezierPath bezierPathWithRect:self.view.frame];

    _penPath = [UIBezierPath bezierPath];
    [_penPath moveToPoint:CGPointMake(penImage.size.width/2.f, penImage.size.height/2.f)];
    [_penPath addLineToPoint:CGPointMake(self.view.frame.size.width - penImage.size.width/2.f, penImage.size.height/2.f)];
    [_penPath addLineToPoint:CGPointMake(self.view.frame.size.width - penImage.size.width/2.f, self.view.frame.size.height - penImage.size.height/2.f)];
    [_penPath addLineToPoint:CGPointMake(penImage.size.width/2.f, self.view.frame.size.height - penImage.size.height/2.f)];
    [_penPath addLineToPoint:CGPointMake(penImage.size.width/2.f, penImage.size.height/2.f)];

    _rectLayer = [[CAShapeLayer alloc] init];
    _rectLayer.path = _drawPath.CGPath;
    _rectLayer.strokeColor = [UIColor greenColor].CGColor;
    _rectLayer.lineWidth = 5.f;
    _rectLayer.fillColor = [UIColor clearColor].CGColor;
    _rectLayer.strokeEnd = 0.f;
    [self.view.layer addSublayer:_rectLayer];

    _pen = [CALayer layer];
    _pen.bounds = CGRectMake(0, 0, 25.f, 25.f);
    _pen.position = CGPointMake(penImage.size.width/2.f, penImage.size.height/2.f);
    _pen.contents = (id)(penImage.CGImage);
    _pen.position = CGPointMake(penImage.size.width/2.f, penImage.size.height/2.f);
    [self.view.layer addSublayer:_pen];
}

- (IBAction)drawRectangle:(id)sender
{
    _rectLayer.strokeEnd = 1.f;

    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    anim.fromValue = (id)[NSNumber numberWithFloat:0];
    anim.toValue = (id)[NSNumber numberWithFloat:1.f];
    anim.duration = 5.f;
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    [_rectLayer addAnimation:anim forKey:@"drawRectStroke"];

    CAKeyframeAnimation *penMoveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    penMoveAnimation.path = _penPath.CGPath;
    penMoveAnimation.rotationMode = kCAAnimationRotateAuto;
    penMoveAnimation.duration = 5.0;
    penMoveAnimation.calculationMode = kCAAnimationPaced;
    [_pen addAnimation:penMoveAnimation forKey:@"followStroke"];
}

EDIT: Added code for pen to follow stroke, heres the 2x image used: http://cl.ly/image/173J271Y003B

Note: The only problem is that when the pen gets closer to the rotating point or corner its still paced with the stroke therefore the pen looks like its behind the stroke a bit until it flips, a simple solution might be to arc the curve, but Im not sure what your overall goal is.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top