使用CALayers的圆形UIView - 只有一些角落 - 如何?

Sag*_*ari 119 iphone xcode objective-c calayer uiview

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

  • 左上方
  • 左下方
  • 右上
  • 下 - 右

按钮上方有一个图像视图(或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]];
Run Code Online (Sandbox Code Playgroud)

上面的代码将圆度应用于所提供视图的每个角.相反,我只想将圆度应用于选定的角落,如 - 顶部/顶部+左侧/底部+右侧等.

可能吗?怎么样?

Stu*_*art 358

从iOS 3.2开始,您可以使用UIBezierPaths 的功能创建一个开箱即用的圆角矩形(其中只有您指定的角是圆角的).然后,您可以将其用作a的路径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;
Run Code Online (Sandbox Code Playgroud)

就是这样 - 在Core Graphics中手动定义形状并没有搞乱,也没有在Photoshop中创建掩蔽图像.该层甚至不需要无效.应用圆角或更改为新角就像定义新角UIBezierPath并将其CGPath用作蒙版图层的路径一样简单.该方法的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];
Run Code Online (Sandbox Code Playgroud)


nev*_*ing 44

在iPhone如何创建一个圆角的UILabel?来自如何在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];
}
Run Code Online (Sandbox Code Playgroud)

MyView只是一个UIImageView子类:

@interface MyView : UIImageView
{
}
Run Code Online (Sandbox Code Playgroud)

我以前从未使用过图形上下文,但我设法将这些代码混合在一起.它缺少两个角落的代码.如果您阅读了代码,您可以看到我是如何实现这一点的(通过删除一些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];
}
Run Code Online (Sandbox Code Playgroud)

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

不要忘记你需要在那里获得QuartzCore框架才能实现.


its*_*ode 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];
Run Code Online (Sandbox Code Playgroud)


onm*_*133 9

在iOS 11中,我们现在只能围绕某些角落

let view = UIView()

view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
Run Code Online (Sandbox Code Playgroud)


Mav*_*ick 6

带有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
    }
}
Run Code Online (Sandbox Code Playgroud)

可以像这样使用:

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


aZt*_*ceR 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; 
Run Code Online (Sandbox Code Playgroud)


小智 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
Run Code Online (Sandbox Code Playgroud)