如何在iOS中将方形图像屏蔽为圆角图像?

Posted

技术标签:

【中文标题】如何在iOS中将方形图像屏蔽为圆角图像?【英文标题】:How to mask a square image into an image with round corners in iOS? 【发布时间】:2009-06-15 14:02:20 【问题描述】:

如何将方形图像蒙版成圆角图像?

【问题讨论】:

【参考方案1】:

您可以使用 CoreGraphics 使用以下代码 sn-p 创建圆角矩形的路径:

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)

    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, 1);
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
    CGContextClosePath(context);
    CGContextRestoreGState(context);

然后调用CGContextClip(context);将其剪辑到矩形路径。现在任何完成的绘图,包括绘制图像,都将被剪裁为圆角矩形。

举个例子,假设“image”是一个UIImage,它在一个drawRect:方法中:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
addRoundedRectToPath(context, self.frame, 10, 10);
CGContextClip(context);
[image drawInRect:self.frame];
CGContextRestoreGState(context);

【讨论】:

这看起来很有用,但是我对CG库不熟悉。如果我有一个 UIImageView/UIImage,我从那里去哪里? 您可能希望使用我在上面添加的代码在视图上实现 drawRect 方法。 一些小的更正 - drawRect 示例包含两个错误。调用addRoundedRectToPath(不是addRoundRectToPath),保存状态调用CGContextSaveGState(不是CGGraphicsSaveGState)。 现在更容易了。系统为此提供了 +[UIBezierPath bezierPathWithRoundedRect:cornerRadius],如下所述。【参考方案2】:

这是一种更简单的方法,适用于 iPhone 3.0 及更高版本。每个基于视图的对象都有一个关联层。每个图层都可以设置一个角半径,这将为您提供您想要的:

UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * layer = [roundedView layer];
[layer setMasksToBounds:YES];
[layer setCornerRadius:10.0];

// You can even add a border
[layer setBorderWidth:4.0];
[layer setBorderColor:[[UIColor blueColor] CGColor]];

要使用这些方法,您可能需要添加:

#import <QuartzCore/QuartzCore.h>

【讨论】:

上面 NilObject 发布的 CoreGraphics 方法在处理动画项目时速度更快。显然,内置的圆角半径效率不高。 谢谢!如果有人遇到这个问题,请确保在你的实现文件中#import ,否则这些方法都不会运行。 这里你分配了一个 UIImageView 对象。当您在 UITableViews 中处理图像时,这不是一个选项。 它只环绕边框 - 不是图像本身【参考方案3】:

我知道这是个老新闻,但只是简单地概括一下:

这里有两个可能的问题:(1) 如何将圆角应用到将显示在屏幕上的 UIView(例如 UIImageView),以及 (2) 我如何对方形图像(即 UIImage)进行遮罩以生成具有圆角的新图像。

对于(1),最简单的当然是使用CoreAnimation并设置view.layer.cornerRadius属性

 // Because we're using CoreAnimation, we must include QuartzCore.h
 // and link QuartzCore.framework in a build phases 
 #import <QuartzCore/QuartzCore.h> 

 // start with an image 
 UIImage * fooImage = [UIImage imageNamed:@"foo.png"];
 // put it in a UIImageView
 UIView * view = [UIImageView alloc] initWithImage:fooImage];
 // round its corners. This mask now applies to the view's layer's *background*
 view.layer.cornerRadius = 10.f
 // enable masksToBounds, so the mask applies to its foreground, the image
 view.layer.masksToBounds = YES;

对于(2),最好的方式是使用UIKit的图形操作:

// start with an image 
UIImage * fooImage = [UIImage imageNamed:@"foo.png"];
CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height);
// set the implicit graphics context ("canvas") to a bitmap context for images
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0);
// create a bezier path defining rounded corners
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.f];
// use this path for clipping in the implicit context
[path addClip];
// draw the image into the implicit context
[fooImage drawInRect:imageRect];
// save the clipped image from the implicit context into an image 
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
// cleanup
UIGraphicsEndImageContext();

问题 (2) 的棘手之处在于,您可能认为可以使用 CoreAnimation 中的 view.layer.mask 属性来完成整个操作。但是你不能因为 CALayer renderInContext: 方法,你用来从蒙版层生成 UIImage 的方法似乎忽略了蒙版。更糟糕的是,renderInContext: 的文档没有提到这一点,只提到了 OSX 10.5 的行为。

一些进一步的背景:上述 (2) 的方法是使用 UIKit 的包装器围绕更基本的 CoreGraphics 功能。您可以直接使用 CoreGraphics 调用来做同样的事情——这就是选择的答案正在做的事情——但是你需要从曲线和直线手动构建圆角矩形贝塞尔路径,你还需要补偿 CoreGraphics 使用相对于 UIKit 翻转的绘图坐标系。

【讨论】:

这虽然运行良好,但可以水平镜像图像。我删除了 CGContextDrawImage((ctx, imageRect, theImage.CGImage); 并将其替换为 [theImage drawInRect:CGRectMake(0,0,imageRect.size.width, imageRect.size.height)]; 这解决了问题。 @zachron 感谢您的更正。我已经重写了这个答案,以完全避免原始 CG。这似乎是基于阅读 Apple 的 developer.apple.com/library/ios/#documentation/2DDrawing/… 中的“使用 Quartz 和 UIKit 绘图”部分推荐的【参考方案4】:

查看这篇文章 - 非常简单的答案

How to set round corners in UI images in iphone

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];

【讨论】:

【参考方案5】:

非常简单。 self.profileImageView.layer.cornerRadius = self.profileImageView.frame.size.width / 2; self.profileImageView.clipsToBounds = YES;

对于每个视图,都有一个捆绑的图层属性。所以上面第一行就是设置图层对象的圆角半径(即CALayer类的一个实例)。要从方形图像制作圆形图像,半径设置为 UIImageView 宽度的一半。例如,如果正方形图像的宽度为 100 像素。半径设置为 50 像素。其次,您必须将 clipsToBounds 属性设置为 YES 才能使图层正常工作。

【讨论】:

【参考方案6】:

这两种方法都有效,但不同之处取决于您使用它的位置。

例如:如果您有一个表格视图,其中的单元格显示图像以及其他标签等,并且您使用图层设置cornerRadius,则滚动将受到很大影响。它变得生涩。

当我在表格视图单元格中使用图层作为图像时遇到了这个问题,并试图找出导致抖动的原因却发现 CALayer 是罪魁祸首。

使用 NilObject 解释的 drawRect 中的第一个解决方案。这就像一种魅力,滚动就像丝绸一样光滑。

另一方面,如果你想在弹出视图等静态视图中使用它,图层是最简单的方法。

正如我所说,这两种方法都很有效,只是您需要根据要使用它的位置来决定。

【讨论】:

【参考方案7】:

我用这个方法。

+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size;
    
      UIImage *img = nil;


        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        UIGraphicsBeginImageContext(rect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context,
                                     color.CGColor);
        CGContextFillRect(context, rect);
        img = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();


      return img;
    

【讨论】:

根据内存管理规则UIGraphicsGetImageFromCurrentImageContext返回的图像对象不需要保留,所以你会在那里泄漏内存。需要保留它的是imageWithColor 的调用者。也许您是因为NSAutoreelasePool(这似乎也很可疑)而添加了保留?【参考方案8】:

在algal 的基础上,这里有一些方法可以很好地放入 UIImage 类别中:


- (UIImage *) roundedCornerImageWithRadius:(CGFloat)radius

    CGRect imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
    UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0); //scale 0 yields better results

    //create a bezier path defining rounded corners and use it for clippping
    UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:radius];
    [path addClip];

    // draw the image into the implicit context
    [self drawInRect:imageRect];

    // get image and cleanup
    UIImage *roundedCornerImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return roundedCornerImage;


+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size andCornerRadius:(CGFloat)radius

    UIImage *image = nil;
    if (size.width == 0 || size.height == 0) 
        size = CGSizeMake(1.0, 1.0);
    
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size,NO,0.0); //yields sharper results than UIGraphicsBeginImageContext(rect.size)
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (context)
    
        CGContextSetFillColorWithColor(context, [color CGColor]);
        if (radius > 0.0) 
            //create a bezier path defining rounded corners and use it for clippping
            UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
            [path addClip];
            CGContextAddPath(context, path.CGPath);
        
        CGContextFillRect(context, rect);
        image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
    return image;

【讨论】:

以上是关于如何在iOS中将方形图像屏蔽为圆角图像?的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中将图像裁剪为正方形

如何在 iOS 中屏蔽 UIViews

如何在 iOS TableViewCell 上实现圆角图像?

如何在 iOS 中将图像裁剪为多边形?

在 Xamarin.Forms 中将图像裁剪为正方形

如何在iOS中将输出(UIView)导出为指定大小的图像