0

我有一个自定义UITableViewCell类,我在我的一个类中使用UITableViewController。我在下面粘贴了它的代码。对不起,如果它有点冗长,但我相信每一点代码都与这个问题有关。在自定义单元格类中,我拍摄一张图片,用 a 对其进行遮罩UIBezierPath以使其成为圆形,创建另一个添加边框和内部阴影的图片(也使用 a UIBezierPath),然后将这两个图片组合起来。

一切正常,除了第一张图像(实际图像,位于底部)在第二张图像(内部阴影,位于顶部)周围溢出一个像素。我试图摆弄CGRect结构的值,但这并没有成功……这是一张图片,说明了我在说什么:

图片溢出

这是自定义的代码UITableViewCell

#import "AZTrackedUserMenuCell.h"
#import "UIImageView+AFNetworking.h"

@interface AZTrackedUserMenuCell ()

@property (nonatomic, strong) UIActivityIndicatorView *ai;

@end

@implementation AZTrackedUserMenuCell

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.ai = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

    CGFloat aiWidth = self.ai.frame.size.width;
    CGFloat aiHeight = self.ai.frame.size.height;

    self.ai.frame = CGRectMake(42.0, 38.0, aiWidth, aiHeight);

    [self addSubview:self.ai];

    [self.ai startAnimating];

    [self displayImage];

    UILabel *usernameLabel = (UILabel *)[self viewWithTag:2];
    if (usernameLabel == nil) {
        usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(95.0, 15.0, 140.0, 21)];
        usernameLabel.tag = 2;
        [self addSubview:usernameLabel];
    }

    usernameLabel.font = [UIFont boldSystemFontOfSize:14.0];
    usernameLabel.textColor = [UIColor colorWithWhite:0.9 alpha:1.000];
    usernameLabel.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.0];

    if (self.user == nil) {
        self.tag = -1;
        usernameLabel.text = @"No user tracked";
    } else {
        self.tag = 0;
        usernameLabel.text = self.user[@"display_name"];
    }


    self.backgroundColor = [UIColor clearColor];
}

- (void)displayImage
{
    UIImageView *avatarImageView = [[UIImageView alloc] initWithFrame:CGRectMake(15.0, 10.0, 84.0, 84.0)];

    if (self.user == nil) {
        avatarImageView.image = [self renderImage:[UIImage imageNamed:@"defaultUserImage"] inImageView:avatarImageView];
        [self.ai stopAnimating];
        self.ai.hidden = YES;
        [self addSubview:avatarImageView];
    } else {
        NSURLRequest *avatarURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:self.user[@"profile_image"]]];
        __weak typeof(avatarImageView) weakAvatarImageView = avatarImageView;
        [avatarImageView setImageWithURLRequest:avatarURLRequest
                               placeholderImage:[UIImage imageNamed:@"no-image"]
                                        success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
                                            weakAvatarImageView.image = [self renderImage:image inImageView:weakAvatarImageView];
                                            [self addSubview:weakAvatarImageView];
                                            [self.ai stopAnimating];
                                        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {

                                        }];
    }

}

- (UIImage *)renderImage:(UIImage *)image inImageView:(UIImageView *)imageView
{
    UIImage *maskedImage = nil;

    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);
    CGContextRef maskContext = UIGraphicsGetCurrentContext();

    UIBezierPath* maskOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, 76.0, 76.0)];
    CGContextSaveGState(maskContext);
    {
        [maskOvalPath addClip];

        [image drawInRect:CGRectMake(0.0, 0.0, 76.0, 76.0)];

        maskedImage = UIGraphicsGetImageFromCurrentImageContext();
    }

    CGContextRestoreGState(maskContext);

    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);

    CGContextRef ssContext = UIGraphicsGetCurrentContext();

    UIColor* fillColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0];
    UIColor* strokeColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.529];
    UIColor* strokeColor2 = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];

    UIColor* shadow = strokeColor;
    CGSize shadowOffset = CGSizeMake(0.1, -0.1);
    CGFloat shadowBlurRadius = 25.0;

    // Stroke and shadow oval path
    UIBezierPath* ssOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, 76.0, 76.0)];
    [fillColor setFill];
    [ssOvalPath fill];

    CGRect ovalBorderRect = CGRectInset(ssOvalPath.bounds, -shadowBlurRadius, -shadowBlurRadius);
    ovalBorderRect = CGRectOffset(ovalBorderRect, -shadowOffset.width, -shadowOffset.height);
    ovalBorderRect = CGRectInset(CGRectUnion(ovalBorderRect, ssOvalPath.bounds), -1, -1);

    UIBezierPath* ovalNegativePath = [UIBezierPath bezierPathWithRect: ovalBorderRect];
    [ovalNegativePath appendPath:ssOvalPath];
    ovalNegativePath.usesEvenOddFillRule = YES;

    // Stroke and shadow image
    UIImage *ss = nil;

    CGContextSaveGState(ssContext);
    {
        CGFloat xOffset = shadowOffset.width + round(ovalBorderRect.size.width);
        CGFloat yOffset = shadowOffset.height;
        CGContextSetShadowWithColor(ssContext,
                                    CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
                                    shadowBlurRadius,
                                    shadow.CGColor);

        [ssOvalPath addClip];
        CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(ovalBorderRect.size.width), 0);
        [ovalNegativePath applyTransform: transform];
        [[UIColor grayColor] setFill];
        [ovalNegativePath fill];

        [strokeColor2 setStroke];
        ssOvalPath.lineWidth = 3;
        [ssOvalPath stroke];

        ss = UIGraphicsGetImageFromCurrentImageContext();
    }
    CGContextRestoreGState(ssContext);

    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSaveGState(context);
    {
        [maskedImage drawInRect:CGRectMake(0.0, 0.0, maskedImage.size.width, maskedImage.size.height)];
        [ss drawInRect:CGRectMake(maskedImage.size.width - ss.size.width, maskedImage.size.height - ss.size.height, ss.size.width, ss.size.height)];

        imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    }
    CGContextRestoreGState(context);

    UIGraphicsEndImageContext();

    return imageView.image;
}

@end

请问这个溢出怎么去掉?

编辑 1:我记录了所有三个图像的大小:

DDLogInfo(@"%f, %f", maskedImage.size.width, maskedImage.size.height);
DDLogInfo(@"%f, %f", ss.size.width, ss.size.height);
DDLogInfo(@"%f, %f", imageView.image.size.width, imageView.image.size.height);

我得到以下输出:

2013-07-01 20:03:47:075 Stackify[25044:c07] 84.000000, 84.000000
2013-07-01 20:03:47:075 Stackify[25044:c07] 84.000000, 84.000000
2013-07-01 20:03:47:075 Stackify[25044:c07] 84.000000, 84.000000

编辑 2:按照@peter-hosey 的建议,我重构了该renderImage:inImageView:方法。我不知道代码是否更好,但这里是:(注意结果是一样的)

- (UIImage *)renderImage:(UIImage *)image inImageView:(UIImageView *)imageView
{
    UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);
    CGContextRef maskContext = UIGraphicsGetCurrentContext();

    UIColor* fillColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0];
    UIColor* strokeColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.529];
    UIColor* strokeColor2 = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];

    UIColor* shadow = strokeColor;
    CGSize shadowOffset = CGSizeMake(0.1, -0.1);
    CGFloat shadowBlurRadius = 25.0;

    UIBezierPath* ssOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, 76.0, 76.0)];
    [fillColor setFill];
    [ssOvalPath fill];

    CGRect ovalBorderRect = CGRectInset(ssOvalPath.bounds, -shadowBlurRadius, -shadowBlurRadius);
    ovalBorderRect = CGRectOffset(ovalBorderRect, -shadowOffset.width, -shadowOffset.height);
    ovalBorderRect = CGRectInset(CGRectUnion(ovalBorderRect, ssOvalPath.bounds), -1, -1);

    UIBezierPath* ovalNegativePath = [UIBezierPath bezierPathWithRect: ovalBorderRect];
    [ovalNegativePath appendPath:ssOvalPath];
    ovalNegativePath.usesEvenOddFillRule = YES;

    UIImage *ss = nil;

    UIBezierPath* maskOvalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, 76.0, 76.0)];
    CGContextSaveGState(maskContext);
    {
        CGFloat xOffset = shadowOffset.width + round(ovalBorderRect.size.width);
        CGFloat yOffset = shadowOffset.height;
        CGContextSetShadowWithColor(maskContext,
                                    CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
                                    shadowBlurRadius,
                                    shadow.CGColor);

        [ssOvalPath addClip];
        CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(ovalBorderRect.size.width), 0);
        [ovalNegativePath applyTransform: transform];
        [[UIColor grayColor] setFill];
        [ovalNegativePath fill];

        [strokeColor2 setStroke];
        ssOvalPath.lineWidth = 3;
        [ssOvalPath stroke];

        ss = UIGraphicsGetImageFromCurrentImageContext();

        [maskOvalPath addClip];
        [image drawInRect:CGRectMake(0.0, 0.0, 76.0, 76.0)];

        UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();

        [maskedImage drawInRect:CGRectMake(0.0, 0.0, maskedImage.size.width, maskedImage.size.height)];
        [ss drawInRect:CGRectMake(maskedImage.size.width - ss.size.width, maskedImage.size.height - ss.size.height, ss.size.width, ss.size.height)];

        imageView.image = UIGraphicsGetImageFromCurrentImageContext();
    }

    CGContextRestoreGState(maskContext);

    UIGraphicsEndImageContext();

    return imageView.image;
}

似乎结果图像并没有溢出,而是质量下降,但我不确定..

4

0 回答 0