创建一个带有圆形顶边的 UIView

Create a UIView with rounded top edge

我想创建一个具有 圆顶边缘 的 UIView,就像这张图片,请问我该怎么做?

想要的结果

不需要的结果

有一次我在 SO 的某个地方找到了这个。它很好用。这是代码:

-(UIView *)roundCornersOnView:(UIView *)view onTopLeft:(BOOL)tl topRight:(BOOL)tr bottomLeft:(BOOL)bl bottomRight:(BOOL)br radius:(float)radius {

    if (tl || tr || bl || br) {
        UIRectCorner corner = (bl ? UIRectCornerBottomLeft : 0) | (br ? UIRectCornerBottomRight : 0) | (tl ? UIRectCornerTopLeft : 0) | (tr ? UIRectCornerTopRight : 0);
        UIView *roundedView = view;
        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(radius, radius)];
        CAShapeLayer *maskLayer = [CAShapeLayer layer];
        maskLayer.frame = roundedView.bounds;
        maskLayer.path = maskPath.CGPath;
        roundedView.layer.mask = maskLayer;
        return roundedView;
    } else {
        return view;
    }

}

让你的视图名称为_tView,然后调用:

_tView = (UIView *)[self roundCornersOnView:_tView onTopLeft:YES topRight:YES bottomLeft:NO bottomRight:NO radius:25.0];

这将给出如下输出:

在故事板中也有一种简单的方法可以做到这一点。

  1. 创建一个没有背景色 (clearColor) 的 UIView。
  2. 在此视图中创建另外两个具有您需要的背景颜色的视图。
  3. 将一个视图放在另一个视图之上,转到右侧面板中的身份检查器。并在用户定义的运行时属性部分添加 "layer.cornerRadius = desiredRadius"。
  4. 您现在有两个带有背景颜色的视图。一个带圆角,一个不带圆角,只需调整它们的位置即可获得您想要的外观,仅此而已。无需编码。

要重新发布我在不同主题中发布的答案:

我现在可以确认这是在iOS 6之后引入的错误。我有一个旧的4s 运行ning iOS 6.1。在那台机器上,这段代码:

  path = [UIBezierPath bezierPathWithRoundedRect: bounds
    byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight
   cornerRadii: CGSizeMake(bounds.size.width/2, bounds.size.width/6)
 ];

创建一个带角 oval-shaped 的圆角矩形。正如您所期望的那样,曲线在曲线的顶部更加平缓,而在两侧更加尖锐:

这是 iOS 6.1 图片,边角应该是这样的:

下面是 运行 来自 iOS 8.1.2 时相同代码的样子:

似乎在 iOS >=7.0 上,它忽略了指定半径的高度,并使用宽度值作为角椭圆的高度和宽度,这迫使它们始终为四分之一圈子。

我在 Apple 的错误报告系统上记录了一个错误。我们会看看他们怎么说。 我建议看到这个问题的其他人也报告一个错误。他们收到的报告越多,他们修复它的可能性就越大。

(忽略底部的 UISwitch。这是之前测试遗留下来的。)

编辑:我编写了构建贝塞尔曲线的代码,该曲线大致近似于 iOS < 7 生成的曲线外观。我刚刚找到 article on approximating circles with bezier curves。使用那篇文章中的控制点,构建我们自己的适用于所有版本 iOS.

bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: 方法并不难

执行此操作的正确方法(或正确方法之一)是使用 UIBezierCurveaddQuadCurveToPoint:controlPoint。您可以从路径到一个点的任何地方绘制二次曲线,使用另一个点作为控制点,这是一种确定结果路径将具有多少弧度和曲线的方法。不过不要忘记,如果您使用图层作为遮罩,您还必须绘制形状的矩形部分,否则遮罩将只是曲线。

真的帮了我大忙 我通过这段代码实现了这个效果:

Swift 3.1

extension UIView {
    func addBottomRoundedEdge(desiredCurve: CGFloat?) {
        let offset: CGFloat = self.frame.width / desiredCurve!
        let bounds: CGRect = self.bounds

        let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2)
        let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
        let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
        let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
        rectPath.append(ovalPath)

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

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

覆盖 UIView 的绘制方法Class。

弯曲顶边

override func draw(_ rect: CGRect) {
        let y:CGFloat = 20
        let curveTo:CGFloat = 0

        let myBezier = UIBezierPath()
        myBezier.move(to: CGPoint(x: 0, y: y))
        myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
        myBezier.addLine(to: CGPoint(x: rect.width, y: rect.height))
        myBezier.addLine(to: CGPoint(x: 0, y: rect.height))
        myBezier.close()
        let context = UIGraphicsGetCurrentContext()
        context!.setLineWidth(4.0)
        //UIColor.white.setFill()
        backgroundColor?.setFill()
        myBezier.fill()
        let maskLayer: CAShapeLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = myBezier.cgPath
        self.layer.mask = maskLayer

    }

对于弧形底边

override func draw(_ rect: CGRect) {

            let y:CGFloat = 15
            let curveTo:CGFloat = 0

            let myBezier = UIBezierPath()
            myBezier.move(to: CGPoint(x: 0, y: rect.height - y ))
            myBezier.addQuadCurve(to: CGPoint(x: rect.width, y:  rect.height - y), controlPoint: CGPoint(x: rect.width / 2, y: rect.height))
            myBezier.addLine(to: CGPoint(x: rect.width, y: 0))
            myBezier.addLine(to: CGPoint(x: 0, y: 0))
            myBezier.close()
            let context = UIGraphicsGetCurrentContext()
            context!.setLineWidth(4.0)
            //UIColor.white.setFill()
            backgroundColor?.setFill()
            myBezier.fill()
            let maskLayer: CAShapeLayer = CAShapeLayer()
            maskLayer.frame = bounds
            maskLayer.path = myBezier.cgPath
            self.layer.mask = maskLayer

        }