如何将圆角添加到UIBezierPath自定义矩形?

时间:2015-07-03 21:57:15

标签: ios swift uibezierpath

我设法创造圆角,但我遇到第一个圆角(右下角)的问题

问题:

  • 我可以在(moveToPoint)方法之前添加(addArcWithCenter)方法吗?
  • 如何摆脱矩形开头的直线(右下角)?

这是我自定义矩形的代码和截图:

let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 300, y: 0))
path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 50), radius:10, startAngle: CGFloat(2 * M_PI / 3), endAngle:CGFloat(M_PI) , clockwise: true)// 2rd rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 10), radius:10, startAngle: CGFloat(M_PI), endAngle:CGFloat(3 * M_PI / 2), clockwise: true)// 3rd rounded corner
// little triangle at the bottom
path.addLineToPoint(CGPoint(x:240 , y:0))
path.addLineToPoint(CGPoint(x: 245, y: -10))
path.addLineToPoint(CGPoint(x:250, y: 0))
path.addArcWithCenter(CGPoint(x: 290, y: 10), radius: 10, startAngle: CGFloat(3 * M_PI / 2), endAngle: CGFloat(2 * M_PI ), clockwise: true)
path.closePath()

enter image description here

5 个答案:

答案 0 :(得分:17)

我认为你所做的事情过于复杂。 UIBezierPath为您提供UIBezierPath(roundedRect:),为什么不使用它?描边圆角矩形;擦掉你要放小三角形的地方;添加三角形;填补复合路径;并划过三角形缺失的两边。就像这样(这只是我碰巧躺在的一些代码 - 当然你应该改变数字以适应你的形状):

let con = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(con, 10, 10)
UIColor.blueColor().setStroke()
UIColor.blueColor().colorWithAlphaComponent(0.4).setFill()
let p = UIBezierPath(roundedRect: CGRectMake(0,0,250,180), cornerRadius: 10)
p.stroke()
CGContextClearRect(con, CGRectMake(20,170,10,11))
let pts = [
    CGPointMake(20,180), CGPointMake(20,200),
    CGPointMake(20,200), CGPointMake(30,180)
]
p.moveToPoint(pts[0])
p.addLineToPoint(pts[1])
p.addLineToPoint(pts[3])
p.fill()
CGContextStrokeLineSegments(con, pts, 4)

enter image description here

答案 1 :(得分:8)

一些观察结果:

  1. 确保使用bounds视图并将其插入线宽的一半。这样可以确保整个描边边框都位于视图的bounds之内。如果您的线宽为1,可能不会那么明显,但是如果线宽较大,则问题会变得更加明显。

  2. 如果使用draw(_:)方法,请不要使用传递给该方法的rect,而应参考bounds(如上所述,插图)。传递给CGRect的{​​{1}}是要绘制的矩形,不一定是完整的draw(_:)。 (通常但并非总是如此,因此总是引用视图的bounds,而不是传递给此方法的bounds。)

    the documentation说(强调):

    视图边界中需要更新的部分。第一次绘制视图时,此矩形通常是视图的整个可见范围。 但是,在随后的绘图操作中,矩形可能仅指定视图的一部分。

  3. 我将给视图的所有各种属性提供一个rect观察者,该观察者将触发重新绘制视图。这样,任何IB覆盖或以编程方式设置的值都将自动反映在结果视图中。

  4. 如果需要,您可以制作整个didSet,并制作属性@IBDesignable,以便可以在Interface Builder中看到它。这不是必需的,但是如果您希望在情节提要或NIB中看到此效果,则很有用。

  5. 恕我直言,虽然您可以使用圆弧圆角,但是使用四边形曲线更容易。您只需指定弧的结束点和矩形的角,然后二次贝塞尔曲线将产生一个很好的圆角。使用此技术,无需计算角度或圆弧的中心。

因此:

@IBInspectable

结果是:

enter image description here

答案 2 :(得分:7)

没关系,我实际上找到了解决方案。

而不是用直线启动代码:

path.moveToPoint(CGPoint(x: 300, y: 0))

我改为以弧形(右上角)开始:

path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner

通过这样做,我有四个圆角,我只需要在代码末尾添加一条直线:

path.closePath()  

以下是代码和屏幕截图:

let path = UIBezierPath()
path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 50), radius:10, startAngle: CGFloat(2 * M_PI / 3), endAngle:CGFloat(M_PI) , clockwise: true)// 2rd rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 10), radius:10, startAngle: CGFloat(M_PI), endAngle:CGFloat(3 * M_PI / 2), clockwise: true)// 3rd rounded corner
// little triangle
path.addLineToPoint(CGPoint(x:240 , y:0))
path.addLineToPoint(CGPoint(x: 245, y: -10))
path.addLineToPoint(CGPoint(x:250, y: 0))
path.addArcWithCenter(CGPoint(x: 290, y: 10), radius: 10, startAngle: CGFloat(3 * M_PI / 2), endAngle: CGFloat(2 * M_PI ), clockwise: true)
path.addLineToPoint(CGPoint(x:300 , y:50))
path.closePath()

enter image description here

答案 3 :(得分:2)

Swift 5 ,其中包含配置变量:

override func draw(_ rect: CGRect) {
    let arrowXOffset: CGFloat = 13
    let cornerRadius: CGFloat = 6
    let arrowHeight: CGFloat = 6

    let mainRect = CGRect(origin: rect.origin, size: CGSize(width: rect.width, height: rect.height - arrowHeight))

    let leftTopPoint = mainRect.origin
    let rightTopPoint = CGPoint(x: mainRect.maxX, y: mainRect.minY)
    let rightBottomPoint = CGPoint(x: mainRect.maxX, y: mainRect.maxY)
    let leftBottomPoint = CGPoint(x: mainRect.minX, y: mainRect.maxY)

    let leftArrowPoint = CGPoint(x: leftBottomPoint.x + arrowXOffset, y: leftBottomPoint.y)
    let centerArrowPoint = CGPoint(x: leftArrowPoint.x + arrowHeight, y: leftArrowPoint.y + arrowHeight)
    let rightArrowPoint = CGPoint(x: leftArrowPoint.x + 2 * arrowHeight, y: leftArrowPoint.y)

    let path = UIBezierPath()
    path.addArc(withCenter: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y + cornerRadius), radius: cornerRadius,
                startAngle: CGFloat(3 * Double.pi / 2), endAngle: CGFloat(2 * Double.pi), clockwise: true)
    path.addArc(withCenter: CGPoint(x: rightBottomPoint.x - cornerRadius, y: rightBottomPoint.y - cornerRadius), radius: cornerRadius,
                startAngle: 0, endAngle: CGFloat(Double.pi / 2), clockwise: true)

    path.addLine(to: rightArrowPoint)
    path.addLine(to: centerArrowPoint)
    path.addLine(to: leftArrowPoint)

    path.addArc(withCenter: CGPoint(x: leftBottomPoint.x + cornerRadius, y: leftBottomPoint.y - cornerRadius), radius: cornerRadius,
                startAngle: CGFloat(Double.pi / 2), endAngle: CGFloat(Double.pi), clockwise: true)
    path.addArc(withCenter: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y + cornerRadius), radius: cornerRadius,
                startAngle: CGFloat(Double.pi), endAngle: CGFloat(3 * Double.pi / 2), clockwise: true)


    path.addLine(to: rightTopPoint)
    path.close()
}

答案 4 :(得分:1)

您无法自动执行此操作。您必须缩短线条,然后使用您想要角半径的半径弧。

因此。您可以将线添加到x-radius,y,而不是向x,y添加线。 然后添加弧。然后下一行从x,y +半径开始。