Add rounded corners to all UIImageViews
Asked Answered
P

6

78

I would like to add some rounded corners to all of the UIImageViews in my project. I have already got the code working, but am having to apply it to every image; should I subclass UIImageView to add this? If so, can someone give me some pointers as to how to do this?

Here is the code

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *mainpath = [[NSBundle mainBundle] bundlePath];
    welcomeImageView.image = [UIImage imageWithContentsOfFile:[mainpath stringByAppendingString:@"/test.png"]];
    welcomeImageView.layer.cornerRadius = 9.0;
    welcomeImageView.layer.masksToBounds = YES;
    welcomeImageView.layer.borderColor = [UIColor blackColor].CGColor;
    welcomeImageView.layer.borderWidth = 3.0;
    CGRect frame = welcomeImageView.frame;
    frame.size.width = 100;
    frame.size.height = 100;
    welcomeImageView.frame = frame;
}
Pushcart answered 31/1, 2010 at 11:37 Comment(2)
Hi Jack - thanks for this, it's exactly what I wanted to do. When I try to use this I get an error 'accessing unknown 'cornerRadius' component of a property', and the same for masksToBounds etc. Oddly the code sense feature in xcode helpfully fills in these properties for me, but the compiler won't compile them. Does the code above work for you on iOS4.0?Dallis
You need to #import <QuartzCore/QuartzCore.h>Bounteous
C
25

You could use a category for UIImage which is an alternate way to subclass a Class and sometimes easier for just small changes.

e.g add a method that returns a UIImage with the rounded corner attributes set.

+(UIImage *)imageWithContentsOfFile:(NSString *)file cornerRadius:(NSInteger)... 

more info on Objective-c categories can be found http://macdevelopertips.com/objective-c/objective-c-categories.html

Coquito answered 31/1, 2010 at 11:50 Comment(6)
Excellent. Thanks a lot, I'll implement a UIImage category - the tutorial over at macdevelopertips.com is very helpful.Pushcart
I was going to describe how to subclass but I like this approach much more.Recur
I'm puzzled. So then 100% of all UIImages will have this. Why not subclass UIImage, something like UIFramedImage?Transcript
here is the link for the above method igframework-iphone-static-library-project.googlecode.com/…Ctenoid
@Transcript actually, using this approach 0% of UIImages will have rounded corners, until you change them to call the new method. This solution does not override existing methods (which you should not do). This can be a cleaner solution than subclassing because it doesn't require a full subclass—which might be overkill since you're not adding any members or new functionality to UIImage—all you want is a UIImage rounded corners w/out code duplication.Crosson
If it's a different method, yes only ones that call that method, so then what you are saying is you think a single Category that's a receptacle for a whole bunch of add-on needs is a cleaner design than a specialized subclass that delegates everything except the one thing we want changed (Decorator/SRP)? Got it.Transcript
S
114

Check this - Rounded Corners on UIImage

The layer modification seems to be the best way.

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * l = [roundedView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:10.0];
Shaneka answered 31/1, 2010 at 12:29 Comment(2)
Thanks. This is essentially what I have already done, however I have used the dot notation to change the properties. I was just wondering if there was an easy was to add this to a subclass so that if I wanted to change the radius I wouldn't have to change every instance of this.Pushcart
-1 This doesn't attempt to answer the question, which is about easily applying the same code to each UIImageView instance.Wendy
C
25

You could use a category for UIImage which is an alternate way to subclass a Class and sometimes easier for just small changes.

e.g add a method that returns a UIImage with the rounded corner attributes set.

+(UIImage *)imageWithContentsOfFile:(NSString *)file cornerRadius:(NSInteger)... 

more info on Objective-c categories can be found http://macdevelopertips.com/objective-c/objective-c-categories.html

Coquito answered 31/1, 2010 at 11:50 Comment(6)
Excellent. Thanks a lot, I'll implement a UIImage category - the tutorial over at macdevelopertips.com is very helpful.Pushcart
I was going to describe how to subclass but I like this approach much more.Recur
I'm puzzled. So then 100% of all UIImages will have this. Why not subclass UIImage, something like UIFramedImage?Transcript
here is the link for the above method igframework-iphone-static-library-project.googlecode.com/…Ctenoid
@Transcript actually, using this approach 0% of UIImages will have rounded corners, until you change them to call the new method. This solution does not override existing methods (which you should not do). This can be a cleaner solution than subclassing because it doesn't require a full subclass—which might be overkill since you're not adding any members or new functionality to UIImage—all you want is a UIImage rounded corners w/out code duplication.Crosson
If it's a different method, yes only ones that call that method, so then what you are saying is you think a single Category that's a receptacle for a whole bunch of add-on needs is a cleaner design than a specialized subclass that delegates everything except the one thing we want changed (Decorator/SRP)? Got it.Transcript
D
16

Rather than subclassing, you can achieve more powerful functionality through simple categories on UIImageView and CALayer.

Create a category on UIImageView like this:

- (void)maskRoundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
    // To round all corners, we can just set the radius on the layer
    if ( corners == UIRectCornerAllCorners ) {
        self.layer.cornerRadius = radius;
        self.layer.masksToBounds = YES;
    } else {
        // If we want to choose which corners we want to mask then
        // it is necessary to create a mask layer.
        self.layer.mask = [CALayer maskLayerWithCorners:corners radii:CGSizeMake(radius, radius) frame:self.bounds];
    }
}

This calls a category method on CALayer:

+ (id)maskLayerWithCorners:(UIRectCorner)corners radii:(CGSize)radii frame:(CGRect)frame {

    // Create a CAShapeLayer
    CAShapeLayer *mask = [CAShapeLayer layer];

    // Set the frame
    mask.frame = frame;

    // Set the CGPath from a UIBezierPath
    mask.path = [UIBezierPath bezierPathWithRoundedRect:mask.bounds byRoundingCorners:corners cornerRadii:radii].CGPath;

    // Set the fill color
    mask.fillColor = [UIColor whiteColor].CGColor;

    return mask;
}

So, this allows you to round any combination (see UIRectCorner) of corners, which is especially handy if you want to put an image in a group style UITableView. There is one caveat when doing this however. Because we've not subclassed UIImageView, we cannot inject any code into layoutSubviews, which means that the mask layer may not be correct. In fact, when configuring cells, the bounds of the image view won't even be set when you call the category method. Hence, you need to ensure the bounds of the image view is set before adding rounded corners (except if using UIRectCornersAllCorners).

Here is some code which does this:

        // Perform corner rounding
        UIRectCorner corners = !UIRectCornerAllCorners;
        if (indexPath.row == 0) 
            corners = UIRectCornerTopLeft;
        if (indexPath.row == numberOfRowsInTheTable)  
            corners |= UIRectCornerBottomLeft;

        if (corners > 0) {
            cell.imageView.bounds = CGRectMake(0.f, 0.f, [self.tableView rowHeight], [self.tableView rowHeight]);
            [cell.imageView maskRoundCorners:corners radius:10.f];
        } else {
            [cell.imageView removeRoundCornersMask];
        }

I have another category which removes rounded corners - all that does is remove any masks and set the cornerRadius to 0.

Dhammapada answered 9/5, 2012 at 11:53 Comment(4)
Great solution. But I am wondering if it wouldn't be better to create class that all view's can access it like UILabel, UIButton, UIView, etc. - kind a universal method?Polydactyl
Never mind. I've just created UIView category that handles all kinds of view's. Thanks!Polydactyl
@BorutTomazin great thought - I was thinking YAGNI, but moving the UIImageView category to UIView would be a great little utility function.Dhammapada
Exactly what I did. Now it can be used on all views that their parent is UIView...Polydactyl
S
5

Yes, you should subclass UIImageView, and use your custom subclass throughout your project.

Smelter answered 31/1, 2010 at 11:46 Comment(2)
Thanks, I thought that would be the best way. Do you know of any good tutorials on using subclasses? Could I use this method with interface builder or should I rewrite my interface in code?Pushcart
Actually, Martinj's answer above is probably easier, saving you from having to use a custom subclass everywhere, in Interface Builder, etc.Malaspina
I
4

You can subclass UIImageView and then if you implement its setNeedsDisplay method the round corners will work on subclasses. (don't forget to import QuartzCore)

-(void)setNeedsDisplay {
    self.layer.cornerRadius = 5;
    self.layer.masksToBounds = YES;
    [self.layer setBorderColor:[[UIColor whiteColor] CGColor]];
    [self.layer setBorderWidth: 2.0];
}
Importunacy answered 23/5, 2012 at 13:26 Comment(1)
You mustn't do this, setNeedsDisplay essentially schedules repaint, and that's it's purpose. You must set up your layer in init method.Abject
B
3

Try this,

coverImage.image = [UIImage imageWithContentsOfFile:@"coverImage.png"]; 
coverImage.layer.masksToBounds = YES;
coverImage.layer.cornerRadius = 10.0;
coverImage.layer.borderWidth = 1.0;
coverImage.layer.borderColor = [[UIColor brown] CGColor];

this may help you.

Briareus answered 16/1, 2013 at 11:13 Comment(1)
-1 This doesn't attempt to answer the question. The question is not about how to produce a rounded UIImageView (this is done successfully in the question's code snippet), but about how to reuse that code effectively.Wendy

© 2022 - 2024 — McMap. All rights reserved.