Eddie
Eddie

Reputation: 1942

Draw Rounded Intersect Lines

I have to create a tab with buttons and some custom border (Images below). Problem is I have to add cornerRadius for each intersect but I'm not sure how to do it properly.

I have this code to draw tabs with border:

private func drawBorder(selectedTab: UIButton) {
        // The Tab frame (below one)
        guard let tabContainerFrame = vTabContainer?.frame else { return }

        let borderColor = selectedTab.titleColor(for: .selected)

        let tabFrame = selectedTab.convert(selectedTab.bounds, to: self)
        let topMargin: CGFloat = 5
        let tabOrigin = CGPoint(x: tabFrame.origin.x, y: tabFrame.origin.y - topMargin)

        // Make paths to draw
        let path = UIBezierPath()

        path.move(to: tabOrigin) // Origin (top left)
        path.addLine(to: CGPoint(x: tabFrame.maxX, y: tabOrigin.y)) // -> right
        path.addLine(to: CGPoint(x: tabFrame.maxX, y: tabFrame.maxY)) // -> down

        if tabFrame.maxX != tabContainerFrame.maxX {
            path.addLine(to: CGPoint(x: tabContainerFrame.maxX, y: tabContainerFrame.origin.y)) // -> right
        }

        path.addLine(to: CGPoint(x: tabContainerFrame.maxX, y: tabContainerFrame.maxY)) // -> Down
        path.addLine(to: CGPoint(x: tabContainerFrame.origin.x, y: tabContainerFrame.maxY)) // -> left
        path.addLine(to: CGPoint(x: tabContainerFrame.origin.x, y: tabContainerFrame.origin.y)) // -> up

        if tabOrigin.x != tabContainerFrame.origin.x {
            path.addLine(to: CGPoint(x: tabOrigin.x, y: tabContainerFrame.origin.y)) // -> right
        }

        // Close the path. This will create the last line automatically.
        path.close()

        // Draw
        let borderLayer = CAShapeLayer()
        borderLayer.path = path.cgPath
        borderLayer.lineCap = kCALineCapRound
        borderLayer.lineJoin = kCALineJoinBevel
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = borderColor?.cgColor
        borderLayer.cornerRadius = 10
        borderLayer.lineWidth = 2
        layer.addSublayer(borderLayer)

        self.borderLayer = borderLayer
    }

This is the result:

Tab1 Tab2

As you can see, even though I add cornerRadius = 10, it just doesn't work. borderLayer.lineCap = kCALineCapRound and borderLayer.lineJoin = kCALineJoinBevel doesn't help also.

Bonus:

I'd like to have a way to implement dynamic @IBInspectable var lineCornerRadius: CGFloat = 10.

Upvotes: 0

Views: 187

Answers (1)

DonMag
DonMag

Reputation: 77462

If you are using UIBezierPath to draw a shape, setting cornerRadius will have no effect on that path.

Instead, you want to use path.addCurve(to: ...) to make your rounded corners.

For example:

enter image description here

  • the green dotted line is tabFrame
  • pt1 is tabFrame's "left" and "top + 10" (your radius)
  • pt2 is tabFrame's "left + 10" and "top"
  • pt3 is the first curve's second "control point" - the top-left corner of tabFrame
  • pt4 is tabFrame's "right - 10" and "top"
  • pt5 is tabFrame's "right" and "top + 10"
  • pt6 is the second curve's second "control point" - the top-right corner of tabFrame

So

path.addCurve(to: pt2, controlPoint1: pt1, controlPoint2: pt3)

adds a curve to pt2 ... from pt1 ... with curve control point of pt3

then:

path.addLine(to: pt4)

adds a line from the current point (pt2) to pt4

then:

path.addCurve(to: pt5, controlPoint1: pt4, controlPoint2: pt6)

adds a curve to pt5 ... from pt4 ... with curve control point of pt6

The rest of your shape is normal line segments.

Upvotes: 3

Related Questions