圆角UIView使用CALayers – 只有一些角落 – 如何?

在我的应用程序中 – 有四个按钮命名如下:

  • 左上角
  • 左下方
  • 右上
  • 底部 – 右侧

在按钮上方有图像视图(或UIView)。

现在,假设用户点击左上角的按钮。 上面的图片/视图应该在特定的角落圆角。

我在使用圆角到UIView有一些困难。

现在我正在使用下面的代码将圆角应用到每个视图:

// imgVUserImg is a image view on IB. imgVUserImg.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"any Url Here"]; CALayer *l = [imgVUserImg layer]; [l setMasksToBounds:YES]; [l setCornerRadius:5.0]; [l setBorderWidth:2.0]; [l setBorderColor:[[UIColor darkGrayColor] CGColor]]; 

上面的代码是将圆度应用到提供的View的每个角落。 相反,我只是想应用圆形选定的角落,如 – 顶/顶+左/底+右等

可能吗? 怎么样?

我使用了答案如何在iPhone上创建一个圆角的UILabel? 和如何是一个圆形矩形视图与iPhone上的透明度完成的代码? 做这个代码。

然后我意识到我会回答错误的问题(给UULabel而不是UIImage),所以我用这个代码来改变它:

http://discussions.apple.com/thread.jspa?threadID=1683876

使用视图模板制作一个iPhone项目。 在视图控制器中添加这个:

 - (void)viewDidLoad { CGRect rect = CGRectMake(10, 10, 200, 100); MyView *myView = [[MyView alloc] initWithFrame:rect]; [self.view addSubview:myView]; [super viewDidLoad]; } 

MyView只是一个UIImageView子类:

 @interface MyView : UIImageView { } 

我以前从来没有使用图形上下文,但我设法蹒跚在一起这个代码。 它缺少两个角落的代码。 如果你阅读代码,你可以看到我是如何实现这个的(通过删除一些CGContextAddArc调用,并删除代码中的一些半径值。所有角落的代码在那里,所以使用它作为一个起点和删除创建角落的部分不需要注意,如果需要,也可以制作具有2或3个圆角的矩形。

代码不完美,但我相信你可以把它整理一下。

 static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, int roundedCornerPosition) { // all corners rounded // CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius); // CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius); // CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, // radius, M_PI / 4, M_PI / 2, 1); // CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, // rect.origin.y + rect.size.height); // CGContextAddArc(context, rect.origin.x + rect.size.width - radius, // rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1); // CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius); // CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, // radius, 0.0f, -M_PI / 2, 1); // CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y); // CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, // -M_PI / 2, M_PI, 1); // top left if (roundedCornerPosition == 1) { CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius); CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius); CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 4, M_PI / 2, 1); CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y); CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y); } // bottom left if (roundedCornerPosition == 2) { CGContextMoveToPoint(context, rect.origin.x, rect.origin.y); CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height); CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y); CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y); CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, M_PI, 1); } // add the other corners here CGContextClosePath(context); CGContextRestoreGState(context); } -(UIImage *)setImage { UIImage *img = [UIImage imageNamed:@"my_image.png"]; int w = img.size.width; int h = img.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, 50, 1); CGContextClosePath(context); CGContextClip(context); CGContextDrawImage(context, rect, img.CGImage); CGImageRef imageMasked = CGBitmapContextCreateImage(context); CGContextRelease(context); CGColorSpaceRelease(colorSpace); [img release]; return [UIImage imageWithCGImage:imageMasked]; } 

替代文字http://nevan.net/skitch/skitched-20100224-092237.png

不要忘了,你需要获得QuartzCore框架才能工作。

从iOS 3.2开始,您可以使用UIBezierPath的功能来创建一个开箱即用的圆角矩形(只有您指定的四舍五入)。 然后,您可以将其用作CAShapeLayer的路径,并将其用作视图图层的蒙版:

 // Create the path (with only the top-left corner rounded) UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(10.0, 10.0)]; // Create the shape layer and set its path CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = imageView.bounds; maskLayer.path = maskPath.CGPath; // Set the newly created shape layer as the mask for the image view's layer imageView.layer.mask = maskLayer; 

就是这样 – 不用在Core Graphics中手动定义形状,也不用在Photoshop中创建遮罩图像。 该层甚至不需要失效。 应用圆角或更改新角点就像定义一个新的UIBezierPath一样简单,并使用其CGPath作为遮罩层的路径。 bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:corners参数bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:方法是一个位掩码,所以多个角落可以通过将它们放在一起进行取整。


编辑:添加一个阴影

如果你想为此添加一个阴影,需要做更多的工作。

因为“ imageView.layer.mask = maskLayer ”应用了蒙版,所以阴影通常不会显示在蒙版之外。 诀窍是使用透明视图,然后将两个子图层( CALayer )添加到视图的图层: shadowLayerroundedLayer 。 两者都需要使用UIBezierPath 。 图像被添加为roundedLayer的内容。

 // Create a transparent view UIView *theView = [[UIView alloc] initWithFrame:theFrame]; [theView setBackgroundColor:[UIColor clearColor]]; // Create the path (with only the top-left corner rounded) UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:theView.bounds byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(10.0f, 10.0f)]; // Create the shadow layer CAShapeLayer *shadowLayer = [CAShapeLayer layer]; [shadowLayer setFrame:theView.bounds]; [shadowLayer setMasksToBounds:NO]; [shadowLayer setShadowPath:maskPath.CGPath]; // ... // Set the shadowColor, shadowOffset, shadowOpacity & shadowRadius as required // ... // Create the rounded layer, and mask it using the rounded mask layer CALayer *roundedLayer = [CALayer layer]; [roundedLayer setFrame:theView.bounds]; [roundedLayer setContents:(id)theImage.CGImage]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; [maskLayer setFrame:theView.bounds]; [maskLayer setPath:maskPath.CGPath]; roundedLayer.mask = maskLayer; // Add these two layers as sublayers to the view [theView.layer addSublayer:shadowLayer]; [theView.layer addSublayer:roundedLayer]; 

我已经在我的代码中的许多地方使用了这个代码,它正常工作100%。 您可以通过更改一个属性“byRoundingCorners:UIRectCornerBottomLeft”来更改任何通讯录

 UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerBottomLeft cornerRadii:CGSizeMake(10.0, 10.0)]; CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = view.bounds; maskLayer.path = maskPath.CGPath; view.layer.mask = maskLayer; [maskLayer release]; 

斯图尔特四舍五入的例子很好。 如果你想要像左上角和右下角那样将多个角倒圆角,这就是如何去做的

 // Create the path (with only the top-left corner rounded) UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageview byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(10.0, 10.0)]; // Create the shape layer and set its path CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = imageview.bounds; maskLayer.path = maskPath.CGPath; // Set the newly created shape layer as the mask for the image view's layer imageview.layer.mask = maskLayer; 

有一个更容易和更快的答案,可能取决于您的需求,也适用于阴影。 您可以将超级图层上的maskToBounds设置为true,并对子图层进行偏移,使其两个角落位于超级图层边界之外,从而有效地将两侧的圆角切除。

当然这只有当你想在同一面上只有两个圆角的时候才起作用,当你从一边切掉几个像素时,图层的内容看起来是一样的。 对于仅在顶部有圆形的条形图非常有效。

感谢分享。 在这里,我想分享一下swift 2.0的解决方案,以便进一步参考这个问题。 (以符合UIRectCorner的协议)

 let mp = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomLeft, .TopLeft], cornerRadii: CGSize(width: 10, height: 10)) let ml = CAShapeLayer() ml.frame = self.bounds ml.path = mp.CGPath self.layer.mask = ml 

看到这个相关的问题 。 您必须将自己的矩形绘制到具有一些圆角的CGPath ,将CGPath添加到您的CGContext ,然后使用CGContextClip剪辑。

你也可以用一个图像的alpha值绘制圆角矩形,然后使用该图像创建一个新图层,并将其设置为图层的mask属性( 请参阅Apple的文档 )。

晚了半年,但我认为目前人们这样做并不是100%正确的。 很多人都有使用UIBezierPath + CAShapeLayer方法干扰自动布局的问题,特别是在故事板上设置的时候。 没有答案,所以我决定添加我自己的。

有一个非常简单的方法来规避:在drawRect(rect: CGRect)函数中绘制圆角。

例如,如果我想为UIView顶部圆角,我会继承UIView,然后在适当的地方使用该子类。

 import UIKit class TopRoundedView: UIView { override func drawRect(rect: CGRect) { super.drawRect(rect) var maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: UIRectCorner.TopLeft | UIRectCorner.TopRight, cornerRadii: CGSizeMake(5.0, 5.0)) var maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = maskPath.CGPath self.layer.mask = maskLayer } } 

这是征服这个问题的最好方法,不需要任何时间去适应。

舍入只有一些角落不会玩自动调整大小或自动布局。

因此,另一个选择是使用常规的cornerRadius并隐藏不希望在另一个视图或其超视界范围之外的角落,确保将其设置为剪辑其内容。

CALayer扩展与Swift 3语法

 extension CALayer { func round(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize) -> Void { let bp = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: cornerRadii) let sl = CAShapeLayer() sl.frame = self.bounds sl.path = bp.cgPath self.mask = sl } } 

它可以用来像:

 let layer: CALayer = yourView.layer layer.round(roundedRect: yourView.bounds, byRoundingCorners: [.bottomLeft, .topLeft], cornerRadii: CGSize(width: 5, height: 5)) 

要添加到答案和补充 ,我在Swift中创建了一个简单的,可重用的UIView 。 根据您的使用情况,您可能需要进行修改(避免在每个布局中创建对象等),但我希望尽可能简单。 如果您不喜欢子类,扩展允许您将其应用于其他视图(如UIImageView )。

 extension UIView { func roundCorners(_ roundedCorners: UIRectCorner, toRadius radius: CGFloat) { roundCorners(roundedCorners, toRadii: CGSize(width: radius, height: radius)) } func roundCorners(_ roundedCorners: UIRectCorner, toRadii cornerRadii: CGSize) { let maskBezierPath = UIBezierPath( roundedRect: bounds, byRoundingCorners: roundedCorners, cornerRadii: cornerRadii) let maskShapeLayer = CAShapeLayer() maskShapeLayer.frame = bounds maskShapeLayer.path = maskBezierPath.cgPath layer.mask = maskShapeLayer } } class RoundedCornerView: UIView { var roundedCorners: UIRectCorner = UIRectCorner.allCorners var roundedCornerRadii: CGSize = CGSize(width: 10.0, height: 10.0) override func layoutSubviews() { super.layoutSubviews() roundCorners(roundedCorners, toRadii: roundedCornerRadii) } } 

以下是你如何将它应用于UIViewController

 class MyViewController: UIViewController { private var _view: RoundedCornerView { return view as! RoundedCornerView } override func loadView() { view = RoundedCornerView() } override func viewDidLoad() { super.viewDidLoad() _view.roundedCorners = [.topLeft, .topRight] _view.roundedCornerRadii = CGSize(width: 10.0, height: 10.0) } } 

结束斯图亚特的答案,你可以有如下的圆角方法:

 @implementation UIView (RoundCorners) - (void)applyRoundCorners:(UIRectCorner)corners radius:(CGFloat)radius { UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)]; CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.frame = self.bounds; maskLayer.path = maskPath.CGPath; self.layer.mask = maskLayer; } @end 

因此,要应用圆角,只需执行以下操作:

 [self.imageView applyRoundCorners:UIRectCornerTopRight|UIRectCornerTopLeft radius:10];