Here’s a relatively easy way to achieve rounded corners on the standard image view in a UITableViewCell:
cell.imageView.layer.masksToBounds = YES; cell.imageView.layer.cornerRadius = 5.0; |
Set this up when you create the cell (make sure you #import <QuartzCore/QuartzCore.h>
at the top, of course). It would appear the UIImageView control creates sublayers to display the actual image content, which is why we use the masksToBounds
property to then clip any sublayers.
I noticed a lot of people are seeking answers to the silly behaviour of UITableView with the grouped (UITableViewStyleGrouped
) style and images:
Images don’t get clipped to the rounded cell border, which looks nasty. This technique is one way to remedy that:
One caveat – due to the inexplicable way the image view within the table view cell scales image content, there’s not really a simple, sensible way to provide an inset margin from the table view cell boundary to complement this rounded border effect.
I tried setting the frame
property of the UIImageView itself (cell.imageView.frame
), as well as setting the frame of the image view’s layer. I also tried applying a scale transform to the layer, with strangely inconsistent results: Setting scale to, say, 50%, made the image view 40x40px, only a pixel or two smaller than the full size. This may be because another entity (the table view cell?) performs scaling of the content, instead of the actual image view; given that my original image was 80×80, a 50% scale would result in 40×40.
My solution was to steer clear of that nonsense and just provide appropriately scaled images straight to the image view. Here’s a simple category on UIImage to scale an image:
@interface UIImage (TPAdditions) - (UIImage*)imageScaledToSize:(CGSize)size; @end @implementation UIImage (TPAdditions) - (UIImage*)imageScaledToSize:(CGSize)size { UIGraphicsBeginImageContext(size); [self drawInRect:CGRectMake(0, 0, size.width, size.height)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } @end |
So, then I just do something like this in the UITableView data provider:
UIImage *image = account.image; if ( image ) { cell.image = [image imageScaledToSize:CGSizeMake(38, 38)]; } |
Sorted.
I found this article via Google search while investigating my own dissatisfaction with this method, which I discovered earlier today. The problem I’m experiencing is a noticeable degradation in the quality of the UITableView scrolling. Mind you, the scrolling is still responsive. However, there is a perceptible jerkiness or flicker to the result that bothered me enough to comment out the lines until I can come up with a better solution. It was as though the corner clipping was being performed repeatedly (albeit quickly) as the table cells scrolled.
In addition to adding a cornerRadius to the images CALayer, I also set a borderColor and borderWidth to frame the image. Maybe this was too much. I’ll explore just the rounding without the border and see how I like the result.
Anyone else observe the same thing?
Hi David – it sounds like your theory is right, that it’s not caching the rendered image, but performing the rendering each time, which may be fairly time-consuming.
It may be worth considering rendering the image with rounded corners yourself and just providing the image view with the finished image.
Hi Michael,
This is exactly what I was looking for after trying a multitude of other settings. Unfortunately it doesn’t work. Any clue as to why? I added QuartzCore framework, and am importing it. Setting the properties as you’ve got them in the part of the cellForRowAtIndexPath right after the cell is created but before it’s returned.
I’ve got a custom table cell built with IB containing a UIImageView, flush left, that’s not getting its corners rounded. Any ideas would be appreciated.
Meanwhile, I’ve had to add a category to UIImage to round the corners, but it doesn’t match the borders of the cell exactly.
Would love to hear if anyone else is having the same issue, or any ideas.
Hi Alec – Sorry about the delay in responding!
It’s hard to take a stab at what might be wrong – have you made sure that the UIImageView is hooked up correctly in IB, and it isn’t just a nil pointer?
Like David I’ve found that the scrolling performance is seriously affected if you apply this rounding to many table view cells. For the odd one or two cells it’s a great tip – I’d already used this technic to add round corners to a map view.
Boy this saved me a lot of research – exactly what I needed after being frustrated by being not able to change the UIImageView’s frame and not wanting to create a custom UITableViewCell since this standard view has everything I need. Thanks Michael!
hai michael ,i have a small problem in using custom classes.
how to use custom classes while we r using it for “UITouch”
am problems in touchesMoved & touches Begin
I’m afraid I don’t understand your question, Khaleeel – would you rephrase? What are you trying to do?
Hi Michael,
I came to the same solution as you, but I get into trouble when I build the app for the new iPhone 4. The images start to look very pixalated. This is because the iPhone 4 scales the images to support the new resolution (they probably get twice as big).
Did you try to get a solution for this? Or do you know how to solve this, without actually creating your own custom UITableViewCell?
Thank you for the quick tip on rounding images in a table – i was forgetting to mask and your post saved the day!
Another simple solution that I could not find anywhere but stumbled across in the documentation is simply moving the image. For some reason, setting the frame does not move the image; however, there are 2 properties indentationLevel and indentationWidth that set the cell margin. I found setting cell.indentationLevel = 1 and leaving the indentationWidth the default value pushes the image over enough to avoid the rounded corners and does not have any performance impact.
Nice find, Philip!
This was extremely helpful; thank you!
Here’s an aspect-ratio-preserving version:
@implementation UIImage (TPAdditions) - (UIImage*)imageScaledToSize:(CGSize)size { double scaleFactor = fmax(fmax(self.size.width / size.width, self.size.height / size.height), 1);
// Then figure out if you need to offset it to center vertically or horizontally float leftOffset = (size.width - newWidth) / 2; float topOffset = (size.height - newHeight) / 2;
CGRect newRect = CGRectMake(leftOffset, topOffset, newWidth, newHeight);
UIGraphicsBeginImageContext(size); [self drawInRect:newRect]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image;
} @end
Where do you put the image category additions +UIImage (TPAdditions)?
Do you put it in its own file and include it?
That’s right, with the interface section in the header file
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
Done
“One caveat – due to the inexplicable way the image view within the table view cell scales image content, there’s not really a simple, sensible way to provide an inset margin from the table view cell boundary to complement this rounded border effect.” The UITableViewCell is laying out the image, text and detailText to its contentView, so if you want to change the size of the imageView you can override -layoutSubviews method of UITableView to adjust the size of the subviews. Remember to call the super implementation prior to do anything. Nice blog!
Good to know! Thanks, Emanuel.
Hi Michael, you did a smart way to display the imageview in tableview cell. i had one problem to showing cclabel above on cell.imageview.image. in my game i used the UITableView to display menu. i displayed image on the left side of the cell and want to show the level on the image so i use cclabel . when i select the row which is highlighted as well as the image highlighted . but the level doesn’t display. in normal mode it display , when row was selected the highlighted image display above on the label. in cocos2d there is Z-index to order the image. but in cocoa touch how to order display of images.
sample code: cell.imageView.image = score==0?[UIImage imageNamed:@”LLock.png”]: [UIImage imageNamed:@”LLevelIndicator.png”];
cell.imageView.highlightedImage= score==0?[UIImage imageNamed:@”LLock.png”]:[UIImage imageNamed:@”LLevelIndicatorHighlighted.png”];
levelLabel.text = score==0?nil:[NSString stringWithFormat:@”%ld”,[indexPath row]];
hey michael, I saw your example above about the uitableviewcells with the rounded images. in your example pictures it looks like you use a UITableViewStyleGrouped with just one element per section.
I like that and I tried to do the same.
my problem: I don’t want rounded corners of the uitableviewcell. I tried
cell.layer.masksToBounds = YES; cell.layer.cornerRadius = 0.0;
but the cell still has a rounded border instead of an angular one. how to make them not rounded?
Hmm, yes, I think that’s custom drawing or something – you’ll probably need to make your own view, with custom appearance (possibly just a UIView with its backing layer’s attributes set appropriately – a white background and a border), and set it as the cell’s background view. You’ll also want to set views for the appropriate states too (e.g. selected)
yeah, your suggestions work ! thank you so much ;)
For things like this I like to use a custom UITableViewCell all together, that implements my own UIImageView property that I can manipulate however I want without getting weird results.
Using a custom cell as well as a custom object that handles the data within the cell I was able to make an extremely fast asynchronous multi-threaded cell loading system that not only displayed the cells to my liking, but once loaded, scrolled smoothly.
Its too much code to post here, but its pretty simple to do, just make a subclass of UITableViewCell and add a UIImageView property to it, use this property to set your image, and you’ll be able to manipulate it however you want.
Thanks man. Luckily, I found your site. I would have never known to add the framework and set the maskToBounds to YES. Thanks again.
Exactly what I was looking for. Thank you!
Very cool.
Cheers.
Thank you for your code – rounded corners look great!
The only problem is that it’s not working so well on iPhone 4’s retina display – it’s better to scale image on transparent background, keeping the same original size:
-(UIImage)imageScaledTo:(CGFloat)scale { // for standard image in table use scale = 0.8 UIGraphicsBeginImageContext(self.size); [self drawInRect:CGRectMake(0.5self.size.width(1-scale), 0.5self.size.height(1-scale), self.size.widthscale,self.size.height*scale)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }
sorry, it’s not working – it looks good but actually rounded corners disapear :-(
Hi Michael
That was a best solution. Could you please suggest how to acheive a kind of ’embossed’ image (little inset …)
Thanks HRS
Thanks HRS!
For Retina support, use: UIGraphicsBeginImageContextWithOptions(size, YES, 2);
I’m new at Xcode and Obj-C and i’ve got a little problem using your code. You have this in your code: UIImage *image = account.image;
What should i change it to? Right now i have this and my app is crashing. UIImage *image = @”testimg.png”;
UIImage *image = [UIImage imageNamed:@"testimg.png"];