开发者

How do I add a UIImage to grouped UITableViewCell so it rounds the corners?

I'm trying to add images to table cells in a grouped UITableView but the corners of the images are not clipped. What's the best way to go about clipping these (besides clipping开发者_如何转开发 them in Photoshop? The table contents are dynamic.)

For example, the first image in a table would need the top left corner rounded only.


This was my solution, which could use a little refactoring:

void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight, BOOL top, BOOL bottom)
{
    float fw, fh;
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(context, fw, fh/2);
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 0);

    NSLog(@"bottom? %d", bottom);

    if (top) {
        CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 3);
    } else {
        CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 0);
    }

    if (bottom) {
        CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 3);
    } else {
        CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 0);
    }

    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 0);
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

- (UIImage *)roundCornersOfImage:(UIImage *)source roundTop:(BOOL)top roundBottom:(BOOL)bottom {
    int w = source.size.width;
    int h = source.size.height;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGContextBeginPath(context);
    CGRect rect = CGRectMake(0, 0, w, h);
    addRoundedRectToPath(context, rect, 4, 4, top, bottom);
    CGContextClosePath(context);
    CGContextClip(context);

    CGContextDrawImage(context, CGRectMake(0, 0, w, h), source.CGImage);

    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    return [UIImage imageWithCGImage:imageMasked];    
}

Implement those functions, then check the indexPath in the cellForRowAtIndexPath delegate method to determine which corner to round.

if (indexPath.row == 0) {
            cell.imageView.image = [self roundCornersOfImage:coverImage roundTop:YES roundBottom:NO];
        } else if (indexPath.row == [indexPath length]) {
            cell.imageView.image = [self roundCornersOfImage:coverImage roundTop:NO roundBottom:YES];
        } else {
            cell.imageView.image = coverImage;
        }


If you're happy to have all four image corners rounded, then you can just do the following when creating the cell:

cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 10.0;

If you also want to inset the image from the boundary, I described a simple category on UIImage to do it here.


There isn't a built-in standard way to do this, but it's not terribly hard to do in your own code. There are examples on how to round corners on an UIImage on the web, see for example http://blog.sallarp.com/iphone-uiimage-round-corners/.


A couple additions/changes, hope it helps someone:

1) roundTop and roundBottom impl changed slightly.

2) made a class method in separate class so reuse is easier, rather than copy/paste everywhere.

First, the new class details:

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface RoundedImages : NSObject {
}
+(UIImage *)roundCornersOfImage:(UIImage *)source roundTop:(BOOL)top roundBottom:(BOOL)bottom;
@end

And its implementation:

#import "RoundedImages.h"

@implementation RoundedImages

void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight, BOOL top, BOOL bottom)
{
    float fw, fh;
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(context, fw, fh/2);

    if (top) {
        CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 3);
        CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 3);
        CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 0);
        CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 0);
    } else {
        CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 0);
        CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 0);
        CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 3);
        CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 3);
    }

    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

+(UIImage *)roundCornersOfImage:(UIImage *)source roundTop:(BOOL)top roundBottom:(BOOL)bottom {
    int w = source.size.width;
    int h = source.size.height;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGContextBeginPath(context);
    CGRect rect = CGRectMake(0, 0, w, h);
    //addRoundedRectToPath(context, rect, 4, 4, top, bottom);
    addRoundedRectToPath(context, rect, 5, 5, top, bottom);
    CGContextClosePath(context);
    CGContextClip(context);

    CGContextDrawImage(context, CGRectMake(0, 0, w, h), source.CGImage);

    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    //return [UIImage imageWithCGImage:imageMasked];
    UIImage *image = [UIImage imageWithCGImage:imageMasked]; 
    CGImageRelease(imageMasked);
    return image;
}

@end

To use in another class (eg, view controller):

#import "RoundedImages.h"

...and later we use it like this...

UIImageView *imageView = nil;
    UIImage *img = [UIImage imageNamed:@"panel.png"];

    if (indexPath.row == 0) {
        imageView = [[UIImageView alloc]initWithImage:[RoundedImages roundCornersOfImage:img roundTop:YES roundBottom:NO]];
    }
    else if (indexPath.row == ([choices count]-1))
    {
        imageView = [[UIImageView alloc]initWithImage:[RoundedImages roundCornersOfImage:img roundTop:NO roundBottom:YES]];
    }
    else {
        imageView = [[UIImageView alloc]initWithImage:img];
    }
    cell.backgroundColor = [UIColor clearColor];
    imageView.clipsToBounds = NO;
    cell.backgroundView = imageView;
    cell.backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
    [cell.backgroundView addSubview:imageView];
    [imageView release];

Note that the "choices" above was just a mutable array I was using on this page that contained the data for the tableview.

I should add that the usage snippet above is used inside your cellForRowAtIndexPath method, and "cell" is a uitableviewcell.

Anyway, works like a champ for me.


There is built-i way if you want to just display the rounded corners. Put the image in a UIImageView and then set the cornerRadius of the layer of the UIImageView. You will also need to tell the UIImageView to clip to bounds but that will give you rounded corners.

UIImageView *myImageView = [[UIImageView alloc] initWithImage:...];
[myImageView setClipsToBounds:YES];
[[myImageView layer] setCornerRadius:5.0f];
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜