0

I'm writing an app with a circular progress bar, and have recently changed it to be drawn with a couple of CAShapeLayers (one for the white background, one for the purple progress) so I can animate the purple line, rather than making new UIBeizerPaths in the drawRect of a UIView.

Having made this change, I've had some issues with how it looks now. Below is a screenshot of each way, and a diff (using “Diff” an image using ImageMagick)

screenshot diffs

My main issue with it is that it looks slightly blurry when using the CAShapeLayers - and I can't for the life of me figure out how to make it look sharper. The other issue is some of the white background is showing through the purple, but I can get around that by changing the width of the white line to be slightly less wide.

The drawRect code as it was originally written is as follows:

- (void)drawRect:(CGRect)rect {

    UIBezierPath *backCircle = [UIBezierPath bezierPath];

    [backCircle addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2)
                      radius:(rect.size.width/2.0f) - 4.0f
                  startAngle:(self.endAngle - self.startAngle) * _percent + self.startAngle
                    endAngle:self.endAngle
                   clockwise:YES];

    backCircle.lineWidth = 5;
    [[UIColor whiteColor] setStroke];
    [backCircle stroke];

    UIBezierPath *bezierPath = [UIBezierPath bezierPath];

    [bezierPath addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2)
                      radius:(rect.size.width/2.0f) - 4.0f
                  startAngle:self.startAngle
                    endAngle:(self.endAngle - self.startAngle) * _percent + self.startAngle
                   clockwise:YES];

    bezierPath.lineWidth = 5;
    [[UIColor purpleColor] setStroke];
    [bezierPath stroke];
}

with the init code:

self.startAngle = M_PI * 1.5;
self.endAngle = self.startAngle + (M_PI * 2);

And then with the 2 layers:

- (void)setUpView
{
    CGFloat startAngle = M_PI * 1.5;
    CGFloat endAngle = startAngle + (M_PI * 2);

    UIBezierPath *processPath = [UIBezierPath bezierPath];
    [processPath addArcWithCenter:self.boundsCenter
                       radius:self.radius
                   startAngle:startAngle
                     endAngle:endAngle
                    clockwise:YES];

    self.backgroundShapeLayer.path = [processPath CGPath];
    self.progressShapeLayer.path = [processPath CGPath];
}

- (CGPoint)boundsCenter
{
    return CGPointMake((self.bounds.size.width ) / 2.0, (self.bounds.size.height ) / 2.0);
}

- (CGFloat)radius
{
    return (self.bounds.size.width / 2.0) - 4.0f;
}

- (CAShapeLayer *)progressShapeLayer
{
    if (_progressShapeLayer == nil) {
        _progressShapeLayer = [CAShapeLayer layer];
        _progressShapeLayer.fillColor = [[UIColor clearColor] CGColor];
        _progressShapeLayer.lineWidth = 5.0;
        _progressShapeLayer.strokeStart = 0.0;
        _progressShapeLayer.contentsScale = [[UIScreen mainScreen] scale];
        [self.layer addSublayer:_progressShapeLayer];
    }

    return _progressShapeLayer;
}

- (CAShapeLayer *)backgroundShapeLayer
{
    if (_backgroundShapeLayer == nil) {
        _backgroundShapeLayer = [CAShapeLayer layer];
        _backgroundShapeLayer.fillColor = [[UIColor clearColor] CGColor];
        _backgroundShapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
        _backgroundShapeLayer.lineWidth = 5.0;
        _backgroundShapeLayer.strokeStart = 0.0;
        _backgroundShapeLayer.contentsScale = [[UIScreen mainScreen] scale];

        [self.layer addSublayer:_backgroundShapeLayer];
    }

    return _backgroundShapeLayer;
}

- (void)setProgress:(CGFloat)progress animated:(BOOL)animated
{
    if(isnan(progress) || progress < 0) return;

    _progress = progress;

    if(!animated) {
        [CATransaction setDisableActions:YES];
    }

    self.progressShapeLayer.strokeColor = [self.progressColour CGColor];
    self.progressShapeLayer.strokeEnd = _progress;
}

I really feel like I'm going a bit crazy staring at the zoomed in screen, but it just doesn't look quite right...

Community
  • 1
  • 1
user2373134
  • 21
  • 1
  • 6
  • Have you got the `contentScale` on the layer set up correctly for the device screen? – Benjohn Feb 19 '14 at 21:19
  • Yep: _progressShapeLayer.contentsScale = [[UIScreen mainScreen] scale]; – user2373134 Feb 19 '14 at 21:34
  • Okay :-) Another thgouth – check [this first answer](http://stackoverflow.com/a/11366907/2547229) about positions of the corners and the pixel grid. – Benjohn Feb 20 '14 at 11:26
  • Thanks for the reply, appreciate it. Don't think this is an issue, I just added the following: – user2373134 Feb 20 '14 at 18:03
  • NSLog(@"frame.origin: %@", NSStringFromCGPoint(self.frame.origin)); NSLog(@"frame.size: %@", NSStringFromCGSize(self.frame.size)); NSLog(@"self.bounds: %@", NSStringFromCGRect(self.bounds)); NSLog(@"self.radius: %f", self.radius); NSLog(@"self.boundsCenter: %@", NSStringFromCGPoint(self.boundsCenter)); returning me: frame.origin: {177, 20} frame.size: {118, 118} self.bounds: {{0, 0}, {118, 118}} self.radius: 55.000000 self.boundsCenter: {59, 59} – user2373134 Feb 20 '14 at 18:05
  • I'm out if ideas then. Sorry! Will reply if I get anything. – Benjohn Feb 22 '14 at 01:37

0 Answers0