Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在其遮罩周围绘制CALayer边框?_Ios_Objective C_Calayer_Mask - Fatal编程技术网

Ios 如何在其遮罩周围绘制CALayer边框?

Ios 如何在其遮罩周围绘制CALayer边框?,ios,objective-c,calayer,mask,Ios,Objective C,Calayer,Mask,因此,我有一个CALayer,它有一个遮罩&我想在这个层的遮罩周围添加边框。例如,我已将三角形遮罩设置为该层,并希望该层周围有边框 有人能帮我解决这个问题吗?一些建议: 使用不透明阴影而不是边框(将产生模糊效果) 创建另一个层,将其背景色设置为您想要的边框颜色,使用比您已经模拟边框宽度的遮罩稍大的遮罩对其进行遮罩,并将其居中放置在层后面(可能不适用于所有形状) 对遮罩图像执行形态学操作以计算边界,例如,使用VimageExplate函数系列(更复杂,可能会遇到性能问题) 如果您知道形状,并且可

因此,我有一个
CALayer
,它有一个遮罩&我想在这个层的遮罩周围添加边框。例如,我已将三角形遮罩设置为该层,并希望该层周围有边框

有人能帮我解决这个问题吗?

一些建议:

  • 使用不透明阴影而不是边框(将产生模糊效果)
  • 创建另一个层,将其背景色设置为您想要的边框颜色,使用比您已经模拟边框宽度的遮罩稍大的遮罩对其进行遮罩,并将其居中放置在层后面(可能不适用于所有形状)
  • 对遮罩图像执行形态学操作以计算边界,例如,使用
    VimageExplate
    函数系列(更复杂,可能会遇到性能问题)
  • 如果您知道形状,并且可以用数学方法描述它,请使用核心图形函数显式绘制它并对其进行笔划
  • 或者,在相同的情况下(数学上已知形状),使用
    CAShapeLayer
    绘制边界

在一般情况下,您无法在遮罩周围轻松设置边框。这就像要求在图像的透明像素周围放置边框一样。也许可以使用图像过滤器来完成。在一些更具体的情况下,如果您使用的是纯CAShapeLayer,那么下面是一个代码示例:

[CATransaction begin];
[CATransaction setDisableActions:YES];

CALayer *hostLayer = [CALayer layer];
hostLayer.backgroundColor = [NSColor blackColor].CGColor;
hostLayer.speed  = 0.0;
hostLayer.timeOffset = 0.0;

CALayer *maskedLayer = [CALayer layer];
maskedLayer.backgroundColor = [NSColor redColor].CGColor;
maskedLayer.position = CGPointMake(200, 200);
maskedLayer.bounds   = CGRectMake(0, 0, 200, 200);

CAShapeLayer *mask = [CAShapeLayer layer];
mask.fillColor = [NSColor whiteColor].CGColor;
mask.position = CGPointMake(100, 100);
mask.bounds   = CGRectMake(0, 0, 200, 200);

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 100, 100);
for (int i=0;  i<20;  i++) {
    double x = arc4random_uniform(2000) / 10.0;
    double y = arc4random_uniform(2000) / 10.0;
    CGPathAddLineToPoint(path, NULL, x, y);
}
CGPathCloseSubpath(path);

mask.path = path;

CGPathRelease(path);

maskedLayer.mask = mask;

CAShapeLayer *maskCopy = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:mask]];
maskCopy.fillColor = NULL;
maskCopy.strokeColor = [NSColor yellowColor].CGColor;
maskCopy.lineWidth = 4;
maskCopy.position = maskedLayer.position;

// Alternately, don't set the position and add the copy as a sublayer
// maskedLayer.sublayers = @[maskCopy];

hostLayer.sublayers = @[maskedLayer,maskCopy];

_contentView.layer = hostLayer;
_contentView.wantsLayer = YES;

[CATransaction commit];
[CATransaction begin];
[CATTransaction setDisableActions:是];
CALayer*主机层=[CALayer层];
hostLayer.backgroundColor=[NSColor blackColor].CGColor;
hostLayer.speed=0.0;
hostLayer.timeOffset=0.0;
CALayer*maskedLayer=[CALayer层];
maskedLayer.backgroundColor=[NSColor redColor].CGColor;
maskedLayer.position=CGPointMake(200200);
maskedLayer.bounds=CGRectMake(0,0200200);
CAShapeLayer*掩码=[CAShapeLayer层];
mask.fillColor=[NSColor whiteColor].CGColor;
mask.position=CGPointMake(100100);
mask.bounds=CGRectMake(0,0,200,200);
CGMutablePathRef path=CGPathCreateMutable();
CGPathMoveToPoint(路径,NULL,100100);

对于(int i=0;i请考虑以下示例代码:

- (void)drawRect:(CGRect)rect {
    CAShapeLayer *maskLayer = [CAShapeLayer layer];

    //Modify to your needs
    CGFloat maskInsetWidth = 5.0f;
    CGFloat maskInsetHeight = 5.0f;
    CGFloat maskCornerRadius = 5.0f;
    CGFloat borderWidth = 2.0f;
    UIColor *borderColor = [UIColor blackColor];

    CGRect insetRect = CGRectInset(self.bounds, maskInsetWidth, maskInsetHeight);
    insetRect.size.width = MAX(insetRect.size.width, 0);
    insetRect.size.height = MAX(insetRect.size.height, 0);

    CGPathRef path = [UIBezierPath bezierPathWithRoundedRect:insetRect cornerRadius:maskCornerRadius].CGPath;

    if (borderWidth > 0.0f && borderColor != nil) {
        CAShapeLayer *borderLayer = [CAShapeLayer layer];

        [borderLayer setPath:path];
        [borderLayer setLineWidth:borderWidth * 2.0f];
        [borderLayer setStrokeColor:borderColor.CGColor];
        [borderLayer setFillColor:[UIColor clearColor].CGColor];

        borderLayer.frame = self.bounds;
        [self.layer addSublayer:borderLayer];
    }
    [maskLayer setPath:path];
    [maskLayer setFillRule:kCAFillRuleEvenOdd];
    maskLayer.frame = self.bounds;
    [self.layer setMask:maskLayer];
}
斯威夫特4


如果子类化
CALayer
,则可以使用所需的掩码对其进行实例化,还可以覆盖
layoutSubLayers
以包含所需的边框。这将适用于所有掩码,并且应该是新的可接受答案

有两种方法可以做到这一点。下面我将使用给定掩码的
路径
,并将其指定给class属性,用于在
布局子层
中构造新边框。此方法可能会被多次调用,因此我还设置了一个布尔值来跟踪它。(也可以将边框指定为类属性,并每次删除/重新添加。目前我使用布尔检查

Swift 3:

class CustomLayer: CALayer {

    private var path: CGPath?
    private var borderSet: Bool = false

    init(maskLayer: CAShapeLayer) {
        super.init()
        self.path = maskLayer.path
        self.frame = maskLayer.frame
        self.bounds = maskLayer.bounds
        self.mask = maskLayer
    }

    override func layoutSublayers() {

        if(!borderSet) {
            self.borderSet = true
            let newBorder = CAShapeLayer()

            newBorder.lineWidth = 12
            newBorder.path = self.path
            newBorder.strokeColor = UIColor.black.cgColor
            newBorder.fillColor = nil

            self.addSublayer(newBorder)
        }

    }

    required override init(layer: Any) {
        super.init(layer: layer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
我的方法是swift3

// Usage:
self.btnGroup.roundCorner([.topRight, .bottomRight], radius: 4.0, borderColor: UIColor.red, borderWidth: 1.0)

// Apply round corner and border. An extension method of UIView.
public func roundCorner(_ corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
    let path = UIBezierPath.init(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))

    let mask = CAShapeLayer()
    mask.path = path.cgPath
    self.layer.mask = mask

    let borderPath = UIBezierPath.init(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let borderLayer = CAShapeLayer()
    borderLayer.path = borderPath.cgPath
    borderLayer.lineWidth = borderWidth
    borderLayer.strokeColor = borderColor.cgColor
    borderLayer.fillColor = UIColor.clear.cgColor
    borderLayer.frame = self.bounds
    self.layer.addSublayer(borderLayer)
}

你最终解决了这个问题吗?实际上,不,我需要这个来显示图层的选择。我最终改变了图层的alpha。@ FahriAzimov,请回顾一下,并考虑我的答案。谢谢!首先,谢谢沃纳。这是一个很好的解决方案,如果你是用编程方式画出的面具。如果这个面具是从图像中设置的呢?这?@FahriAzimov您可以尝试从图像中提取路径:使用或代替
archivedDataWithRootObject
+
unarchiveObjectWithData
要创建精确副本,创建新层可能会更快(
[CAShapeLayer new]
)只需再次手动设置其
边界
路径
。@Cœur,考虑到您的评论,我更新了swift 4的代码。
// Usage:
self.btnGroup.roundCorner([.topRight, .bottomRight], radius: 4.0, borderColor: UIColor.red, borderWidth: 1.0)

// Apply round corner and border. An extension method of UIView.
public func roundCorner(_ corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
    let path = UIBezierPath.init(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))

    let mask = CAShapeLayer()
    mask.path = path.cgPath
    self.layer.mask = mask

    let borderPath = UIBezierPath.init(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let borderLayer = CAShapeLayer()
    borderLayer.path = borderPath.cgPath
    borderLayer.lineWidth = borderWidth
    borderLayer.strokeColor = borderColor.cgColor
    borderLayer.fillColor = UIColor.clear.cgColor
    borderLayer.frame = self.bounds
    self.layer.addSublayer(borderLayer)
}