How to add a circular mask to a UIImageview and change the frame and centers while doing so?

13,649

Solution 1

Hope this will help

    CAShapeLayer *circle = [CAShapeLayer layer];
    // Make a circular shape
    UIBezierPath *circularPath=[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, _imgView.frame.size.width, _imgView.frame.size.height) cornerRadius:MAX(_imgView.frame.size.width, _imgView.frame.size.height)];

    circle.path = circularPath.CGPath;

    // Configure the apperence of the circle
    circle.fillColor = [UIColor blackColor].CGColor;
    circle.strokeColor = [UIColor blackColor].CGColor;
    circle.lineWidth = 0;

    imgViewToClipCircular.layer.mask=circle;

Solution 2

Ok, so since the center in my case changes, using the mask is not ging to help. So the easy and clean way is to have a custom UiImageView and clip the draw path.

So for that, subclass UIView and draw the image inside it and clip the path. Here is the overriden the drawRect function,

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(context, self.bounds);
    CGContextClip(context);
    //The subclass of UIView has a UIImageview as property
    [_image drawInRect:rect];    
}

FYI, you can not subclass UIImageView itself and override drawRect , coz it won't call the drawRect,

The UIImageView class is optimized to draw its images to the display. UIImageView will not call drawRect: a subclass. If your subclass needs custom drawing code, it is recommended you use UIView as the base class.

Share:
13,649
akshaynhegde
Author by

akshaynhegde

Updated on June 05, 2022

Comments

  • akshaynhegde
    akshaynhegde almost 2 years

    I would like to add a circular mask to UIImageVIew. Here is the function that am using to add the mask..

    - (void) addMaskToBounds:(CGRect) maskBounds
    {
        CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    
        CGPathRef maskPath = CGPathCreateWithEllipseInRect(maskBounds, NULL);
        maskLayer.bounds = maskBounds;
        [maskLayer setPath:maskPath];
        [maskLayer setFillColor:[[UIColor blackColor] CGColor]];
        maskLayer.position = CGPointMake(maskBounds.size.width/2, maskBounds.size.height/2);
    
        [self.imageView.layer setMask:maskLayer];
    }
    

    Am able to add the mask but the problem occurs since am changing the image frame and center along with it. The image is enlarged and made small based on the user actions. Hence I would have to add the mask twice when small and when enlarged. So Since am animating the frame change, while animating the image become distorted, or displaced. How do I overcome this ?

    I guess its best explained with an example project. Here I have created a Demo project https://github.com/akshaynhegde/MaskImage on GitHub, just run it to see my problem and let me know how resolve the problem.

  • CVertex
    CVertex over 10 years
    The custom UIImageView solution was what I was previously using, so this solution worked was appropriate for me. It also looks closer to what iOS 7 does
  • Mrug
    Mrug over 9 years
    You can change centre of mask layer also.
  • Layynezz
    Layynezz almost 8 years
    This doesn't solve the initial question of how to animate frame changes to UIImageView when using a mask at all...
  • Carl Smith
    Carl Smith over 7 years
    I found this code very handy because I needed an off-center circular mask for a view I was creating. First I used layer.cornerRadius to make the view circular in Interface Builder. Then I used this code with a negative Y value in the Bezier path to create a mask for it. The resulting shape looks a lot like an American football, which is what I needed.
  • RobP
    RobP almost 7 years
    Note that your comment is not quite correct -- this subclass of UIView must have a UIImage as a property, not a UIImageView