反转UIBezierPath用于单侧拐角

sta*_*Man 2 objective-c uiview cashapelayer ios uibezierpath

我想创建一个蒙版路径,其最终输出将是一个带凹面的角.

我已经创建了一个UIBezierPath使用该-bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:方法并指定只需要对一个角进行舍入(在此示例中UIRectCornerBottomLeft),我认为通过反转此路径,我应该得到首先要切割的内容.
为此,我正在尝试,-bezierPathByReversingPath但它似乎没有任何区别(有或没有,因为我得到正常的bezier路径,而不是相反)

这是我到目前为止所尝试的:

UIView *vwTest = [[UIView alloc] init];
[vwTest setFrame:CGRectMake(100.0f, 100.0f, 100.0f, 100.0f)];
[vwTest setBackgroundColor:[UIColor redColor]];
[self.view addSubview:vwTest];

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:vwTest.bounds
                                               byRoundingCorners:UIRectCornerBottomLeft
                                                     cornerRadii:CGSizeMake(50.0f, 50.0f)];

//get reverse path but doesn't seem to work as I think it should
maskPath = [maskPath bezierPathByReversingPath]; 

CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setFrame:vwTest.bounds];
[maskLayer setPath:maskPath.CGPath];

[vwTest.layer setMask:maskLayer];
[vwTest.layer setMasksToBounds:YES];
[vwTest setNeedsDisplay];
Run Code Online (Sandbox Code Playgroud)

根据下面的图像,我想要实现的是显示红色部分UIView并消除其余区域.

maskPath理念


暂时,我在subview上做subit,并将一个子视图的颜色与主视图的背景颜色同步(很糟糕,但至少我得到了所需的输出):

[self.view setBackgroundColor:[UIColor lightGrayColor]];

UIView *vwTest = [[UIView alloc] init];
[vwTest setFrame:CGRectMake(100.0f, 100.0f, 100.0f, 100.0f)];
[vwTest setBackgroundColor:[UIColor redColor]];
[self.view addSubview:vwTest];

UIView *vwPatch = [[UIView alloc] init];
[vwPatch setFrame:vwTest.bounds];
[vwPatch setBackgroundColor:vwTest.superview.backgroundColor];
[vwTest addSubview:vwPatch];

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:vwPatch.bounds
                                               byRoundingCorners:UIRectCornerBottomLeft
                                                     cornerRadii:CGSizeMake(50.0f, 50.0f)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setFrame:vwPatch.bounds];
[maskLayer setPath:maskPath.CGPath];

[vwPatch.layer setMask:maskLayer];
[vwPatch.layer setMasksToBounds:YES];
[vwPatch setNeedsDisplay];
Run Code Online (Sandbox Code Playgroud)

有人,请指出我正确的方向.

Ric*_*ich 6

通过查看问题中的代码我假设你想要左下角(正如你所使用的那样UIRectCornerBottomLeft)是半径为30的凹面.你不能使用,bezierPathByReversingPath因为所有它都是字面上反转路径,它也说在文档中:

反转路径不一定会在渲染时更改路径的外观.

编辑:
现在已经在问题中添加了图像,OP需要形状的反转:

CAShapeLayer *mask = [CAShapeLayer layer];
mask.frame = view.layer.bounds;

UIBezierPath *path = [UIBezierPath bezierPath];
CGFloat radius = 50;
CGRect rect = mask.bounds;
[path moveToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect))];
[path addLineToPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect) - radius)];
[path addArcWithCenter:CGPointMake(CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect) - radius) radius:radius startAngle:M_PI endAngle:M_PI_2 clockwise:NO];
[path closePath];

mask.path = path.CGPath;
view.layer.mask = mask;
Run Code Online (Sandbox Code Playgroud)

然后,路径的形状是问题中OPs图像的红色位.


张贴图片前的答案 - 可能会用于其他人

以下代码将生成此形状:

形状

CGFloat cornerRadius = 30;

CGRect rect = CGRectMake(0, 0, 200, 100);

UIBezierPath *path = [UIBezierPath bezierPath];

// Draw the complete sides
[path moveToPoint:rect.origin];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect))];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect))];

// Stop short for the start of the arc
[path addLineToPoint:CGPointMake(CGRectGetMinX(rect) + cornerRadius, CGRectGetMaxY(rect))];

// Concave arc
[path addArcWithCenter:CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)) radius:cornerRadius startAngle:0 endAngle:M_PI_2 * 3 clockwise:NO];

// Complete the path
[path closePath];
Run Code Online (Sandbox Code Playgroud)

更新:有用的类别

类别,UIBezierPath所以你可以选择哪个角(UIRectCorners的位掩码)和半径.

UIBezierPath + RDHConcaveCorners.h

@interface UIBezierPath (RDHConcaveCorners)

+(instancetype)bezierPathWithRoundedRect:(CGRect)rect byConcaveRoundingCorners:(UIRectCorner)corners cornerRadius:(CGFloat)radius;

@end
Run Code Online (Sandbox Code Playgroud)

UIBezierPath + RDHConcaveCorners.m

@implementation UIBezierPath (RDHConcaveCorners)

+(instancetype)bezierPathWithRoundedRect:(CGRect)rect byConcaveRoundingCorners:(UIRectCorner)corners cornerRadius:(CGFloat)cornerRadius
{
    CGFloat halfWidth = CGRectGetWidth(rect) / 2;
    CGFloat halfHeight = CGRectGetHeight(rect) / 2;
    if (cornerRadius > halfWidth || cornerRadius > halfHeight) {
        cornerRadius = MIN(halfWidth, halfHeight);
    }

    UIBezierPath *path = [self bezierPath];

    CGPoint topLeft = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
    if (corners & UIRectCornerTopLeft) {
        [path moveToPoint:CGPointMake(topLeft.x, topLeft.y + cornerRadius)];
        [path addArcWithCenter:topLeft radius:cornerRadius startAngle:M_PI_2 endAngle:0 clockwise:NO];
    } else {
        [path moveToPoint:topLeft];
    }

    CGPoint topRight = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
    if (corners & UIRectCornerTopRight) {
        [path addLineToPoint:CGPointMake(topRight.x - cornerRadius, topRight.y)];
        [path addArcWithCenter:topRight radius:cornerRadius startAngle:M_PI endAngle:M_PI_2 clockwise:NO];
    } else {
        [path addLineToPoint:topRight];
    }

    CGPoint bottomRight = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
    if (corners & UIRectCornerBottomRight) {
        [path addLineToPoint:CGPointMake(bottomRight.x, bottomRight.y - cornerRadius)];
        [path addArcWithCenter:bottomRight radius:cornerRadius startAngle:M_PI_2 * 3 endAngle:M_PI clockwise:NO];

    } else {
        [path addLineToPoint:bottomRight];
    }

    CGPoint bottomLeft = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));
    if (corners & UIRectCornerBottomLeft) {
        [path addLineToPoint:CGPointMake(bottomLeft.x + cornerRadius, bottomLeft.y)];
        [path addArcWithCenter:bottomLeft radius:cornerRadius startAngle:0 endAngle:M_PI_2 * 3 clockwise:NO];
    } else {
        [path addLineToPoint:bottomLeft];
    }

    // Complete the path
    [path closePath];

    return path;
}

@end
Run Code Online (Sandbox Code Playgroud)