在我的应用程序中 - 有四个按钮命名如下:
按钮上方有一个图像视图(或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]];
以上代码将圆度应用于所提供视图的每个角。相反,我只是想将圆度应用于选定的角落,如 - 顶部/顶部+左侧/底部+右侧等。
有可能吗?怎么样?
答案 0 :(得分:357)
从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
作为遮罩层的路径即可。 corners
方法的bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
参数是一个位掩码,因此可以通过将它们组合在一起来舍入多个角。
如果您想为此添加阴影,则需要做更多工作。
因为“imageView.layer.mask = maskLayer
”应用了一个遮罩,所以阴影通常不会显示在它外面。诀窍是使用透明视图,然后将两个子图层(CALayer
s)添加到视图的图层:shadowLayer
和roundedLayer
。两者都需要使用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];
答案 1 :(得分:44)
我使用How do I create a round cornered UILabel on the iPhone?处的答案和How is a rounded rect view with transparency done on iphone?的代码来制作此代码。
然后我意识到我回答了错误的问题(给了一个圆形的UILabel而不是UIImage)所以我用这段代码来改变它:
http://discussions.apple.com/thread.jspa?threadID=1683876
使用View模板制作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];
}
alt text http://nevan.net/skitch/skitched-20100224-092237.png
不要忘记你需要在那里使用QuartzCore框架才能实现这一点。
答案 2 :(得分:18)
我在代码中的很多地方都使用过这段代码,它可以100%正确地工作。您可以通过更改一个属性“byRoundingCorners:UIRectCornerBottomLeft”来更改任何corder
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];
答案 3 :(得分:8)
在iOS 11中,我们现在只能围绕某些角落
let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
答案 4 :(得分:5)
Stuarts围绕特定角落的示例效果很好。如果你想像左上角和右上角那样绕过多个角落,那就是如何做到这一点
// 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;
答案 5 :(得分:5)
感谢分享。在这里,我想在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
答案 6 :(得分:4)
根据您的需要,可以使用更简单,更快速的答案,也可以使用阴影。你可以将superlayer上的maskToBounds设置为true,并偏移子层,使它们的2个角位于超层边界之外,有效地切掉两边的圆角。
当然,只有当你想在同一侧只有2个圆角并且从一侧切掉几个像素时图层的内容看起来相同时,这才有效。非常适合将条形图仅放在顶部。
答案 7 :(得分:4)
使用 Swift 3及以上语法
的CALayer扩展程序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))
答案 8 :(得分:3)
见this related question。您必须使用部分圆角将{7}}绘制为自己的矩形,将CGPath
添加到CGPath
,然后使用{{{}修剪到CGContext
1}}。
您还可以将带有Alpha值的圆角矩形绘制到图像,然后使用该图像创建一个新图层,将其设置为图层的CGContextClip
属性(see Apple's documentation)。
答案 9 :(得分:2)
仅对某些角落进行舍入不会对自动调整大小或自动布局感到满意。
所以另一个选择是使用常规cornerRadius
并隐藏你不想在另一个视图下或在其超视图范围之外的角落,确保它被设置为剪辑其内容。
答案 10 :(得分:2)
迟到了五年,但我认为目前人们这样做的方式并非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
}
}
这是解决问题的最好方法,并且根本不需要任何时间来适应。
答案 11 :(得分:1)
要添加到answer和addition,我在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)
}
}
答案 12 :(得分: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];
答案 13 :(得分:0)
我建议定义一个图层的蒙版。掩码本身应该是具有专用路径的CAShapeLayer
对象。您可以使用下一个UIView扩展(Swift 4.2):
extension UIView {
func round(corners: UIRectCorner, with radius: CGFloat) {
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
).cgPath
layer.mask = maskLayer
}
}