带边框的cornerRadius:边框周围有毛刺

时间:2014-08-28 14:16:17

标签: ios objective-c calayer

我的申请主要是以圆形和边界为基础的。

我使用UIView的图层属性来给出角半径和边框。

但我面临的问题是角落不清楚。

我得到以下结果:

的UIButton

screenshot of a button with rounded corners and a border

的UIImageView

screenshot of an image view with rounded corners and a border

您可以观察到白色或灰色边框周围的细边框线。

这是我的代码:

button.layer.borderWidth = 2.0;
button.layer.borderColor = [[UIColor whiteColor] CGColor];
button.layer.cornerRadius = 4;

button.clipsToBounds = YES;

我已经寻求解决这个问题,但我没有取得成功。

我尝试了button.layer.masksToBounds = YES,但没有效果。

我错过了什么吗?或者还有其他方法可以比CALayer提供更好的结果吗?

6 个答案:

答案 0 :(得分:14)

我尝试了很多解决方案并使用UIBezierPath结束。

我创建UIView类别并添加方法以制作圆形矩形和边框。

这是该类别的方法:

- (void)giveBorderWithCornerRadious:(CGFloat)radius borderColor:(UIColor *)borderColor andBorderWidth:(CGFloat)borderWidth
{
    CGRect rect = self.bounds;

    //Make round
        // Create the path for to make circle
        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                       byRoundingCorners:UIRectCornerAllCorners
                                                             cornerRadii:CGSizeMake(radius, radius)];

        // Create the shape layer and set its path
        CAShapeLayer *maskLayer = [CAShapeLayer layer];

        maskLayer.frame = rect;
        maskLayer.path  = maskPath.CGPath;

        // Set the newly created shape layer as the mask for the view's layer
        self.layer.mask = maskLayer;

    //Give Border
        //Create path for border
        UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                         byRoundingCorners:UIRectCornerAllCorners
                                                               cornerRadii:CGSizeMake(radius, radius)];

        // Create the shape layer and set its path
        CAShapeLayer *borderLayer = [CAShapeLayer layer];

        borderLayer.frame       = rect;
        borderLayer.path        = borderPath.CGPath;
        borderLayer.strokeColor = [UIColor whiteColor].CGColor;
        borderLayer.fillColor   = [UIColor clearColor].CGColor;
        borderLayer.lineWidth   = borderWidth;

        //Add this layer to give border.
        [[self layer] addSublayer:borderLayer];
}

我知道在这篇惊人的文章中使用UIBezierPathThinking like a Bézier path

我从这两个链接获得了大部分代码:

注意:这是类别方法,因此自我表示调用此方法的视图。像UIButton,UIImageView等。

答案 1 :(得分:9)

这是我的Swift版@ CRDave' s answer作为UIView的扩展:

protocol CornerRadius {
    func makeBorderWithCornerRadius(radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat)
}

extension UIView: CornerRadius {

    func makeBorderWithCornerRadius(radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        let rect = self.bounds;

        let maskPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let maskLayer = CAShapeLayer()
        maskLayer.frame = rect
        maskLayer.path  = maskPath.CGPath

        // Set the newly created shape layer as the mask for the view's layer
        self.layer.mask = maskLayer

        //Create path for border
        let borderPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let borderLayer = CAShapeLayer()

        borderLayer.frame       = rect
        borderLayer.path        = borderPath.CGPath
        borderLayer.strokeColor = borderColor.CGColor
        borderLayer.fillColor   = UIColor.clearColor().CGColor
        borderLayer.lineWidth   = borderWidth * UIScreen.mainScreen().scale

        //Add this layer to give border.
        self.layer.addSublayer(borderLayer)
    }

}

答案 2 :(得分:6)

这是Kamil Nomtek.com's answer更新为 Swift 3 + 并进行了一些改进(主要是语义/命名和使用类协议)。

protocol RoundedBorderProtocol: class {
    func makeBorder(with radius: CGFloat, borderWidth: CGFloat, borderColor: UIColor)
}

extension UIView: RoundedBorderProtocol {
    func makeBorder(with radius: CGFloat, borderWidth: CGFloat, borderColor: UIColor) {
        let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = maskPath.cgPath

        // Set the newly created shape layer as the mask for the view's layer
        layer.mask = maskLayer

        //Create path for border
        let borderPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: radius, height: radius))

        // Create the shape layer and set its path
        let borderLayer = CAShapeLayer()

        borderLayer.frame = bounds
        borderLayer.path = borderPath.cgPath
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.fillColor = UIColor.clear.cgColor

        //The border is in the center of the path, so only the inside is visible.
        //Since only half of the line is visible, we need to multiply our width by 2.
        borderLayer.lineWidth = borderWidth * 2

        //Add this layer to display the border
        layer.addSublayer(borderLayer)
    }
}

答案 3 :(得分:3)

CRDave的答案效果很好但有一个缺陷:当多次调用大小变化时,它会不断添加图层。而是应该更新以前的图层 请参阅下面的更新ObjC版本。对于swift,请相应调整。

//  UIView+Border.h
#import <UIKit/UIKit.h>

@interface UIView (Border)
- (void)setBorderWithCornerRadius:(CGFloat)radius
                            color:(UIColor *)borderColor
                            width:(CGFloat)borderWidth;
@end

//  UIView+Border.m
#import "UIView+Border.h"

@implementation UIView (Border)
- (void)setBorderWithCornerRadius:(CGFloat)radius
                            color:(UIColor *)borderColor
                            width:(CGFloat)borderWidth {
    CGRect rect = self.bounds;

    //Make round
    // Create the path for to make circle
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                   byRoundingCorners:UIRectCornerAllCorners
                                                         cornerRadii:CGSizeMake(radius, radius)];

    // Create the shape layer and set its path
    CAShapeLayer *maskLayer = [CAShapeLayer layer];

    maskLayer.frame = rect;
    maskLayer.path  = maskPath.CGPath;

    // Set the newly created shape layer as the mask for the view's layer
    self.layer.mask = maskLayer;

    //Give Border
    //Create path for border
    UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rect
                                                     byRoundingCorners:UIRectCornerAllCorners
                                                           cornerRadii:CGSizeMake(radius, radius)];

    // Create the shape layer and set its path
    NSString *layerName = @"ig_border_layer";
    CAShapeLayer *borderLayer = (CAShapeLayer *)[[[self.layer sublayers] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name == %@", layerName]] firstObject];
    if (!borderLayer) {
        borderLayer = [CAShapeLayer layer];
        [borderLayer setName:layerName];
        //Add this layer to give border.
        [[self layer] addSublayer:borderLayer];
    }

    borderLayer.frame       = rect;
    borderLayer.path        = borderPath.CGPath;
    borderLayer.strokeColor = [UIColor whiteColor].CGColor;
    borderLayer.fillColor   = [UIColor clearColor].CGColor;
    borderLayer.lineWidth   = borderWidth;
}
@end

答案 4 :(得分:0)

de.'s answer worked much better for me而不是CRDave的答案。

我必须从Swift进行翻译,所以我想继续翻译并发布:

extension UIView {
    func giveBorderWithCornerRadius(cornerRadius r: CGFloat, borderColor c: UIColor, strokeWidth w: CGFloat) {
        let rect = self.bounds

        let maskPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: r, height: r))

        let maskLayer = CAShapeLayer()

        maskLayer.frame = rect
        maskLayer.path = maskPath.cgPath

        self.layer.mask = maskLayer

        let borderPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: r, height: r))

        let layerName = "border_layer"
        var borderLayer: CAShapeLayer? = self.layer.sublayers?.filter({ (c) -> Bool in
            if c.name == layerName {
                return true
            } else {
                return false
            }
        }).first as? CAShapeLayer

        if borderLayer == nil {
            borderLayer = CAShapeLayer()
            borderLayer!.name = layerName
            self.layer.addSublayer(borderLayer!)
        }

        borderLayer!.frame = rect
        borderLayer!.path = borderPath.cgPath
        borderLayer!.strokeColor = c.cgColor
        borderLayer!.fillColor = UIColor.clear.cgColor
        borderLayer!.lineWidth = w
    }
}

我正在从layoutSubviews()调用该方法

答案 5 :(得分:-3)

删除

button.layer.borderWidth = 0.3;
button.layer.borderColor = [[UIColor blueMain] CGColor];