如何绘制一个矩形的角(没有连接它们的线)

How to draw a just the corners of a rectangle (without lines connecting them)

我有一个 CGRect 值,需要在其周围绘制边框。我只想在没有任何连接线的情况下绘制角。

像这样...

如何使用 swift 绘制此图?

这是一个自定义 UIView class,它用四个角绘制自己。您可以设置各种属性以获得所需的外观。

class CornerRect: UIView {
    var color = UIColor.black {
        didSet {
            setNeedsDisplay()
        }
    }
    var radius: CGFloat = 5 {
        didSet {
            setNeedsDisplay()
        }
    }
    var thickness: CGFloat = 2 {
        didSet {
            setNeedsDisplay()
        }
    }
    var length: CGFloat = 30 {
        didSet {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        color.set()

        let t2 = thickness / 2
        let path = UIBezierPath()
        // Top left
        path.move(to: CGPoint(x: t2, y: length + radius + t2))
        path.addLine(to: CGPoint(x: t2, y: radius + t2))
        path.addArc(withCenter: CGPoint(x: radius + t2, y: radius + t2), radius: radius, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 3 / 2, clockwise: true)
        path.addLine(to: CGPoint(x: length + radius + t2, y: t2))

        // Top right
        path.move(to: CGPoint(x: frame.width - t2, y: length + radius + t2))
        path.addLine(to: CGPoint(x: frame.width - t2, y: radius + t2))
        path.addArc(withCenter: CGPoint(x: frame.width - radius - t2, y: radius + t2), radius: radius, startAngle: 0, endAngle: CGFloat.pi * 3 / 2, clockwise: false)
        path.addLine(to: CGPoint(x: frame.width - length - radius - t2, y: t2))

        // Bottom left
        path.move(to: CGPoint(x: t2, y: frame.height - length - radius - t2))
        path.addLine(to: CGPoint(x: t2, y: frame.height - radius - t2))
        path.addArc(withCenter: CGPoint(x: radius + t2, y: frame.height - radius - t2), radius: radius, startAngle: CGFloat.pi, endAngle: CGFloat.pi / 2, clockwise: false)
        path.addLine(to: CGPoint(x: length + radius + t2, y: frame.height - t2))

        // Bottom right
        path.move(to: CGPoint(x: frame.width - t2, y: frame.height - length - radius - t2))
        path.addLine(to: CGPoint(x: frame.width - t2, y: frame.height - radius - t2))
        path.addArc(withCenter: CGPoint(x: frame.width - radius - t2, y: frame.height - radius - t2), radius: radius, startAngle: 0, endAngle: CGFloat.pi / 2, clockwise: true)
        path.addLine(to: CGPoint(x: frame.width - length - radius - t2, y: frame.height - t2))

        path.lineWidth = thickness
        path.stroke()
    }
}

示例用法:

let cr = CornerRect(frame: CGRect(x: 0, y: 0, width: 300, height: 500))
cr.color = .yellow
cr.thickness = 5
cr.backgroundColor = .white

将其复制并粘贴到 playground 中。尝试不同的属性值。

您绘制这些形状的方式与超人穿紧身衣的方式相同:一次一条腿。将形状分为三个部分:垂直腿、形成圆角的 90 度弧和水平腿。现在依次画出它们。

我将通过展示如何绘制 一个 角来进行说明;其他三个角相似且对称,留作 reader.

的练习。

假设 r 是我们的矩形并且我们处于绘图上下文中(例如 UIView 的 draw(_:) 或图像视图图形上下文)。让我们做一些初步假设(随意更改它们):

UIColor.yellow.setStroke()
let segLength : CGFloat = 40
let cornerSize : CGFloat = 10
let lineWidth : CGFloat = 6

现在我们只是形成一条描述角的一条腿、圆角弧和角的另一条腿的贝塞尔曲线路径,并对其进行描边:

 let p = UIBezierPath()
 p.lineWidth = lineWidth
 // draw top left corner
 p.move(to: CGPoint(x:r.minX, y:r.minY + segLength + cornerSize))
 p.addLine(to: CGPoint(x:r.minX, y:r.minY + cornerSize))
 p.addArc(withCenter: CGPoint(x:r.minX + cornerSize, y:r.minY + cornerSize),
    radius: cornerSize,
    startAngle: CGFloat.pi,
    endAngle: CGFloat.pi * 3.0 / 2.0,
    clockwise: true)
p.addLine(to:CGPoint(x:r.minX + segLength + cornerSize, y:r.minY))
p.stroke()

结果如下所示(我将背景涂成蓝色以便于查看,并且放大了一点):

其他三个角的工作方式完全相同,只是更改了需要更改的明显内容。

因为我花了一段时间才弄明白,所以我将分享 "obvious things that would need to be changed" 使用 @matt 的回答来完成矩形的其余部分 :)

let p = UIBezierPath()
p.lineWidth = lineWidth
// draw top left corner
p.move(to: CGPoint(x:r.minX, y:r.minY + segLength + cornerSize))
p.addLine(to: CGPoint(x:r.minX, y:r.minY + cornerSize))
p.addArc(withCenter: CGPoint(x:r.minX + cornerSize, y:r.minY + cornerSize),
            radius: cornerSize, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 1.5, clockwise: true)
p.addLine(to:CGPoint(x:r.minX + segLength + cornerSize, y:r.minY))
// draw top right corner
p.move(to: CGPoint(x:r.maxX - segLength - cornerSize, y:r.minY ))
p.addLine(to: CGPoint(x:r.maxX - cornerSize, y:r.minY ))
p.addArc(withCenter: CGPoint(x:r.maxX - cornerSize, y:r.minY + cornerSize),
            radius: cornerSize, startAngle: CGFloat.pi * 1.5, endAngle: 0, clockwise: true)
p.addLine(to:CGPoint(x:r.maxX, y:r.minY + segLength + cornerSize))
// draw bottom right corner
p.move(to: CGPoint(x:r.maxX, y:r.maxY - segLength - cornerSize))
p.addLine(to: CGPoint(x:r.maxX, y:r.maxY - cornerSize ))
p.addArc(withCenter: CGPoint(x:r.maxX - cornerSize, y:r.maxY - cornerSize),
radius: cornerSize, startAngle: 0, endAngle: CGFloat.pi * 0.5, clockwise: true)
p.addLine(to:CGPoint(x:r.maxX - segLength - cornerSize, y:r.maxY))
// draw bottom left corner
p.move(to: CGPoint(x:r.minX + segLength + cornerSize, y:r.maxY))
p.addLine(to: CGPoint(x:r.minX + cornerSize, y:r.maxY ))
p.addArc(withCenter: CGPoint(x:r.minX + cornerSize, y:r.maxY - cornerSize),
radius: cornerSize, startAngle: CGFloat.pi * 0.5, endAngle: CGFloat.pi, clockwise: true)
p.addLine(to:CGPoint(x:r.minX, y:r.maxY - segLength - cornerSize))
p.stroke()