iOSGeek iOSGeek - 3 months ago 28x
iOS Question

Animate progress with filling the color of the border width of a UIImageView layer

I have am UIImageView and I have made it to be circle with a width layer like in this image :

enter image description here

User can update the image and upload new one, I have a progress call back while image is uploaded. What I want is to animate the border with color while the image is uploaded, for example when user click upload the border start from top with green color and fill the width according to the progress.

I tried with this code:

CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithArcCenter:CGPointZero radius:27 startAngle:-M_PI_2 endAngle:2 * M_PI - M_PI_2 clockwise:YES].CGPath;
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor greenColor].CGColor;
circle.lineWidth = 4;

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 10;
animation.removedOnCompletion = NO;
animation.fromValue = @(0);
animation.toValue = @(1);
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circle addAnimation:animation forKey:@"drawCircleAnimation"];

[imageView.layer.sublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
[imageView.layer addSublayer:circle];

But It shows the circle in wrong position and this aproch does not take a progress, it's static is there any way to fill the border width of the layer of UIImageView according to progress ?


UIImageView is meant to show the images. I would not suggest changing it's behaviour. Even though you subclass the UIImageView and try to draw something in it, the drawRect of it will not get called. Let the imageView be imageView and use UIView for the rest I suggest you to subclass the UIView and then draw a bezier path in it and animate the bezier path curve, You can later add the imageview to the uiview .

UIView subclass:

- (void)drawRect:(CGRect)rect {
    [self drawImageHolderViewFrame:rect startAngle:_startAngle];

- (void)drawImageHolderViewFrame: (CGRect)frame startAngle: (CGFloat)startAngle
    CGRect ovalRect = CGRectMake(CGRectGetMinX(frame) , CGRectGetMinY(frame) , frame.size.width-10, frame.size.height-10);
    UIBezierPath* ovalPath = [UIBezierPath bezierPath];
    [ovalPath addArcWithCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)) radius: CGRectGetWidth(ovalRect) / 2 startAngle: -91 * M_PI/180 endAngle: -startAngle * M_PI/180 clockwise: YES];
    [UIColor.redColor setStroke];
    ovalPath.lineWidth = 2;
    [ovalPath stroke];

viewController class:

    [super viewDidAppear:animated];
    _imageHolderView=[[MyView alloc]initWithFrame:CGRectMake(20, 20, 100, 100)];
    _imageHolderView.backgroundColor=[UIColor clearColor];
    [self.view addSubview: _imageHolderView];
    [self startTImer];

    NSTimer *timer=[NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(animateBorder) userInfo:nil repeats:YES];

    if (_startAngle<=-270) {
    [_imageHolderView setNeedsDisplay];

This would give you:

enter image description here

Now you can add the imageview as a subview to the view you just created.

enter image description here