如何在UIView上创建带有角度的角落?

7

这里有很多关于如何使UIView的圆角化的问题。不幸的是,我找不到有关如何制作带有倾斜角落的内容。我应该如何制作一个corners被削成45度角的UIView

如果您能向我展示如何使任意单个角落切成角度,您甚至可以得到额外的(比喻性的)金星。

编辑:参考此链接,其中有一个类似于此解决方案的实现。 我只是不知道需要更改什么。


如果你想让像素透明,我记得CoreGraphics可以胜任这项工作。你试过了吗? - user529758
@H2CO3 我不太确定你的意思。你是指使用带有剪裁角的图像作为背景颜色吗? - Thane Brimhall
@Tahne 不,我的意思是使用CGContext*()函数编程绘制透明像素。 - user529758
@H2CO3 实际上,我还没有尝试过那个,而且我甚至不确定如何做。如果你知道的话,我很想在下面看到答案。 :) - Thane Brimhall
1
我不够勇敢 :) 我不是Quartz超级迷,也不知道这个问题的答案,而且现在已经是凌晨1点了。但如果你能等几个小时,我会尽力解决这个问题的。 - user529758
3个回答

7

首先,您需要一个带有斜角的路径:

- (CGPathRef) makeAnglePathWithRect: (CGRect)rect withSize:(float) s {

    CGPoint one = CGPointMake( rect.origin.x +s, rect.origin.y);
    CGPoint two = CGPointMake( rect.origin.x + rect.size.width - s, rect.origin.y);

    CGPoint three = CGPointMake( rect.origin.x + rect.size.width, rect.origin.y +s);
    CGPoint four = CGPointMake( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height -s);

    CGPoint five = CGPointMake( rect.origin.x + rect.size.width-s, rect.origin.y + rect.size.height);
    CGPoint six = CGPointMake(rect.origin.x+s, rect.origin.y + rect.size.height);

    CGPoint seven = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height-s);
    CGPoint eight = CGPointMake(rect.origin.x, rect.origin.y + s);

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path,NULL,one.x, one.y);
    CGPathAddLineToPoint(path,NULL,two.x, two.y);
    CGPathAddLineToPoint(path,NULL,three.x, three.y);
    CGPathAddLineToPoint(path,NULL,four.x, four.y);
    CGPathAddLineToPoint(path,NULL,five.x, five.y);
    CGPathAddLineToPoint(path,NULL,six.x, six.y);
    CGPathAddLineToPoint(path,NULL,seven.x, seven.y);
    CGPathAddLineToPoint(path,NULL,eight.x, eight.y);
    CGPathAddLineToPoint(path,NULL,one.x, one.y);

    return path;
}

接下来需要使用路径来指定一个掩码:

CAShapeLayer *maskLayer = [CAShapeLayer layer];
CGRect bounds = CGRectMake(0.0f, 0.0f, 100, 100); //figure out your bounds

[maskLayer setFrame:bounds];
CGPathRef p = [self makeAnglePathWithRect:bounds withSize:20.0];
maskLayer.path = p;
_myview.layer.mask = maskLayer;

如果您想从任何一个角落中去除角度,请操作点1-8,删除“s”值。您可以使用大小参数更改从角落中切出的三角形的大小。


接受此解决方案,因为尽管它更长,但我认为它更加可定制。如果您要处理所有角落,您应该查看其他答案。 - Thane Brimhall
我在此授予我的象征性金星! :) - Thane Brimhall
1
谢谢!我考虑过通过将点放入数组并循环遍历它们来进行代码高尔夫,以便于CGPathAddLineToPoint,但出于清晰度的目的,我决定将其保留为原样。 - nont
1
绝对的天才!!太棒了 :) - Jack Solomon

4
从 @nont 获得灵感,使用扩展程序,我编写了这个片段:
extension UIView {

    public enum Corner: Int {
        case TopRight
        case TopLeft
        case BottomRight
        case BottomLeft
        case All
    }

    public func blendCorner(corner corner: Corner, length: CGFloat = 20.0) {
        let maskLayer = CAShapeLayer()
        var path: CGPathRef?
        switch corner {
        case .All:
            path = self.makeAnglePathWithRect(self.bounds, topLeftSize: length, topRightSize: length, bottomLeftSize: length, bottomRightSize: length)
        case .TopRight:
            path = self.makeAnglePathWithRect(self.bounds, topLeftSize: 0.0, topRightSize: length, bottomLeftSize: 0.0, bottomRightSize: 0.0)
        case .TopLeft:
            path = self.makeAnglePathWithRect(self.bounds, topLeftSize: length, topRightSize: 0.0, bottomLeftSize: 0.0, bottomRightSize: 0.0)
        case .BottomRight:
            path = self.makeAnglePathWithRect(self.bounds, topLeftSize: 0.0, topRightSize: 0.0, bottomLeftSize: 0.0, bottomRightSize: length)
        case .BottomLeft:
            path = self.makeAnglePathWithRect(self.bounds, topLeftSize: 0.0, topRightSize: 0.0, bottomLeftSize: length, bottomRightSize: 0.0)
        }
        maskLayer.path = path
        self.layer.mask = maskLayer
    }

    private func makeAnglePathWithRect(rect: CGRect, topLeftSize tl: CGFloat, topRightSize tr: CGFloat, bottomLeftSize bl: CGFloat, bottomRightSize br: CGFloat) -> CGPathRef {
        var points = [CGPoint]()

        points.append(CGPointMake(rect.origin.x + tl, rect.origin.y))
        points.append(CGPointMake(rect.origin.x + rect.size.width - tr, rect.origin.y))
        points.append(CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + tr))
        points.append(CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - br))
        points.append(CGPointMake(rect.origin.x + rect.size.width - br, rect.origin.y + rect.size.height))
        points.append(CGPointMake(rect.origin.x + bl, rect.origin.y + rect.size.height))
        points.append(CGPointMake(rect.origin.x, rect.origin.y + rect.size.height - bl))
        points.append(CGPointMake(rect.origin.x, rect.origin.y + tl))

        let path = CGPathCreateMutable()
        CGPathMoveToPoint(path, nil, points.first!.x, points.first!.y)
        for point in points {
            if point != points.first {
                CGPathAddLineToPoint(path, nil, point.x, point.y)
            }
        }
        CGPathAddLineToPoint(path, nil, points.first!.x, points.first!.y)
        return path
    }

}

这样,您可以轻松地混合您的角落:

let view = UIView()
view.blendCorner(corner: .TopRight)
// or view.blendCorner(corner: .All)

3

这里是一种实现方法。假设有:

const CGFloat kRadius = 20.0; //'radius' of the corner clip

并且在您的视图中有以下属性:

@property (nonatomic,strong) CAShapeLayer *maskLayer;

您可以设置一个简单的遮罩层,带有斜角连接线(非常容易实现您想要的45度角):

CAShapeLayer *maskLayer = [CAShapeLayer layer];

maskLayer.lineWidth = kRadius * 2.0;
maskLayer.lineJoin = kCALineJoinBevel;
maskLayer.strokeColor = [[UIColor blackColor] CGColor];

self.layer.mask = self.maskLayer = maskLayer;

在适当的时间(例如在您的-[ViewClass layoutSublayersOfLayer:]方法中),只需将您的遮罩层路径设置为由半径插入的矩形路径:

self.maskLayer.path = CGPathCreateWithRect(CGRectInset(self.bounds,kRadius,kRadius), NULL);

这是一种不必手动绘制路径的方法。您基本上是使用斜角线连接来完成这部分工作。


这是一个很棒的解决方案!有没有办法让它与任何一个角落配合工作? - Thane Brimhall

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