将UIView的顶部圆角化并添加边框

20

我在一个圆角分类中有以下代码。我还想画一个边框,但是边框不会显示在圆角部分。

enter image description here

这是代码:

- (void) roundTopCorners:(CGFloat) radius
{
    self.layer.masksToBounds = YES;

    CGRect bounds = self.bounds;
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(radius, radius)];

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = bounds;
    maskLayer.path = maskPath.CGPath;
    maskLayer.strokeColor = [UIColor redColor].CGColor;

    self.layer.mask = maskLayer;
}

请注意,如果您尝试在动态调整大小的视图上使用此种框架(例如响应自动旋转),则需要更加小心,因为图层无法利用自动布局。在这种情况下,您最好的解决方案可能是创建一个自定义的UITextField,并实现layerClass以返回一个自定义的图层类,该类动态调整大小与上面创建的图层类似。@David Berry。实际上并不难,如果您想要调整所有这些图层的大小,请将所有代码放在viewDidAppear中,它会起作用! - Ernie Sender
4个回答

39

遮罩层不会被绘制,只用于计算遮罩。请尝试:

-(void)roundCorners:(UIRectCorner)corners radius:(CGFloat)radius
{
    CGRect bounds = self.bounds;
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
                                                   byRoundingCorners:corners
                                                         cornerRadii:CGSizeMake(radius, radius)];

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = bounds;
    maskLayer.path = maskPath.CGPath;

    self.layer.mask = maskLayer;

    CAShapeLayer*   frameLayer = [CAShapeLayer layer];
    frameLayer.frame = bounds;
    frameLayer.path = maskPath.CGPath;
    frameLayer.strokeColor = [UIColor redColor].CGColor;
    frameLayer.fillColor = nil;

    [self.layer addSublayer:frameLayer];
}

-(void)roundTopCornersRadius:(CGFloat)radius
{
    [self roundCorners:(UIRectCornerTopLeft|UIRectCornerTopRight) radius:radius];
}

-(void)roundBottomCornersRadius:(CGFloat)radius
{
    [self roundCorners:(UIRectCornerBottomLeft|UIRectCornerBottomRight) radius:radius];
}

您当前看到的框架是UITextField的普通框架,因此请将框架样式设置为无。您还需要调整插图以弥补由于框架样式设置为无而通常没有插图的事实。


请注意,如果您尝试在动态调整大小的视图上使用此种框架样式(例如响应自动旋转),则需要更加小心,因为图层无法利用自动布局。在这种情况下,您最好的解决方案可能是创建一个自定义的UITextField,并实现layerClass以返回一个自定义的图层类,该类动态调整大小类似于上面创建的图层。 - David Berry
3
这是一个不错的方法。但边框厚度可能不会正确。这是因为边框的描边线条是一半在蒙版内,一半在蒙版外。很容易修复 - 只需添加以下内容:frameLayer.lineWidth = borderWidth*2;其中borderWidth是您想要的边框宽度。 - BooTooMany
@BooTooMany 在某个时候,类似的东西在那里考虑到了线宽。我想我实际上是通过适当的量插入路径,但将厚度加倍效果相同且更简单。 - David Berry
如何在UITableViewCell中调用这些方法 - reza_khalafi

13

David Berry 的回答的 Swift 版本:

func roundCorners(corners:UIRectCorner, radius:CGFloat) {
    let bounds = self.bounds

    let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSizeMake(radius, radius))

    let maskLayer = CAShapeLayer()
    maskLayer.frame = bounds
    maskLayer.path = maskPath.CGPath

    self.layer.mask = maskLayer

    let frameLayer = CAShapeLayer()
    frameLayer.frame = bounds
    frameLayer.path = maskPath.CGPath
    frameLayer.strokeColor = UIColor.redColor().CGColor
    frameLayer.fillColor = nil

    self.layer.addSublayer(frameLayer)
}

func roundTopCornersRadius(radius:CGFloat) {
    self.roundCorners([UIRectCorner.TopLeft, UIRectCorner.TopRight], radius:radius)
}

func roundBottomCornersRadius(radius:CGFloat) {
    self.roundCorners([UIRectCorner.BottomLeft, UIRectCorner.BottomRight], radius:radius)
}

棒极了,伙计们。谢谢! - Wez

4

这可能是一个很晚的答案,但我想分享一下我基于不同人在类似问题上给出的答案所得出的解决方案。我从上面Vojtech的答案中得到了很大的帮助。

extension UIView {
    func EZRoundCorners(corners:UIRectCorner, radius: CGFloat) -> CAShapeLayer {
        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.CGPath
        self.layer.mask = mask
        return mask
    }

    func EZRoundCornersWithBorder(corners:UIRectCorner, radius:CGFloat, color:UIColor, width:CGFloat) -> CAShapeLayer {

        let mask = self.EZRoundCorners(corners, radius: radius)

        // Add border
        let borderLayer = EZCALayer()
        borderLayer.path = mask.path // Reuse the Bezier path
        borderLayer.fillColor = UIColor.clearColor().CGColor
        borderLayer.strokeColor = color.CGColor
        borderLayer.lineWidth = width
        borderLayer.frame = self.bounds
        self.layer.addSublayer(borderLayer)
        return borderLayer
    }

    func removeEZLayers () {
        for layer in self.layer.sublayers! {
            if layer is EZCALayer {
                layer.removeFromSuperlayer()
            }
        }
    }
}

class EZCALayer : CAShapeLayer {
}

我继承自CAShapeLayer,因此如果我不再需要使用边框子层,可以将其删除。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接