如何在 UIView 上制作斜角?

Posted

技术标签:

【中文标题】如何在 UIView 上制作斜角?【英文标题】:How can I make angled corners on a UIView? 【发布时间】:2013-02-22 23:57:45 【问题描述】:

这里有很多关于使UIView 的角变圆的问题。不幸的是,我找不到任何关于如何制作有角度的角的信息。我怎样才能制作一个 UIView 以 45 度角切角?

如果你能告诉我如何让任何人以一定角度切角,你甚至可以获得额外的(象征性的)金星。

编辑:作为参考,here's a link 到一个我怀疑与此解决方案有类似实现的问题。我只是不知道我必须改变什么。

【问题讨论】:

如果您使像素透明,IIRC CoreGraphics 就可以完成这项工作。你试过了吗? @H2CO3 我不太确定你的意思。您的意思是使用带有剪角的图像作为背景颜色吗? @Tahne 不,我的意思是使用CGContext*() 函数以编程方式绘制透明像素。 @H2CO3 实际上,我还没有尝试过,我什至不知道该怎么做。如果你知道怎么做,我有兴趣在下面看到答案。 :) 我不够勇敢 :) 我不是一个 Quartz 超级怪胎,而且我不知道这是在我的头上,反正现在是凌晨 1 点,但如果你等一下几个小时后,我会看看我能做什么...... 【参考方案1】:

首先你需要一个有角的路径:

- (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”值。您可以使用 size 参数更改从角上切出的三角形的大小。

【讨论】:

接受这个解决方案,因为即使它更长,我认为它更可定制。如果你打算做所有的角落,你应该看看另一个答案。 我特此授予我的比喻金星! :) 谢谢!我考虑通过将点放在一个数组中并在它们上循环以获得 CGPathAddLineToPoint 来进行代码打高尔夫球,但为了清楚起见,决定保留它。 绝对的天才!!太棒了:)【参考方案2】:

从@nont 中汲取灵感并使用扩展,我编写了这个 sn-p:

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);

这是一种无需手动绘制路径的每一部分的方法。您实际上是在使用斜角线连接来为您完成这项工作。

【讨论】:

这是一个很好的解决方案!有没有办法让它与任何一个角落一起工作?

以上是关于如何在 UIView 上制作斜角?的主要内容,如果未能解决你的问题,请参考以下文章

iphone:如何在 UIVIEW 上制作透明蒙版

如何在 Swift 中制作圆形 UIView

如何使用 UIView 在单选按钮上制作多行标题

如何在不添加另一个 UIView 的情况下为情节提要中的 uitableViewCell 制作等宽分隔符?

如何在 UIView 上绘制渐变封面

如何以编程方式在 UIview 中制作圆角和边?