Skip to content

Instantly share code, notes, and snippets.

@micheltlutz
Last active August 23, 2024 09:39
Show Gist options
  • Save micheltlutz/de304ce9559605792f30056b5b693fe3 to your computer and use it in GitHub Desktop.
Save micheltlutz/de304ce9559605792f30056b5b693fe3 to your computer and use it in GitHub Desktop.
Apply border around tableView Sections
/**
Extension for UITableViewController or UIViewController as you prefer
*/
extension UITableViewController {
func colorSection(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cornerRadius: CGFloat = 0.0
cell.backgroundColor = UIColor.clear
let layer: CAShapeLayer = CAShapeLayer()
let pathRef: CGMutablePath = CGMutablePath()
//dx leading an trailing margins
let bounds: CGRect = cell.bounds.insetBy(dx: 0, dy: 0)
var addLine: Bool = false
if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
} else if indexPath.row == 0 {
pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.minY),
tangent2End: CGPoint(x: bounds.midX, y: bounds.minY),
radius: cornerRadius)
pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY),
tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
radius: cornerRadius)
pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
addLine = true
} else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY),
tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY),
radius: cornerRadius)
pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY),
tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
radius: cornerRadius)
pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
} else {
pathRef.addRect(bounds)
addLine = true
}
layer.path = pathRef
layer.strokeColor = UIColor.lightGray.cgColor
layer.lineWidth = 0.5
layer.fillColor = UIColor.white.cgColor
if addLine == true {
let lineLayer: CALayer = CALayer()
let lineHeight: CGFloat = (1 / UIScreen.main.scale)
lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width, height: lineHeight)
lineLayer.backgroundColor = UIColor.clear.cgColor
layer.addSublayer(lineLayer)
}
let backgroundView: UIView = UIView(frame: bounds)
backgroundView.layer.insertSublayer(layer, at: 0)
backgroundView.backgroundColor = .white
cell.backgroundView = backgroundView
}
}
@md445
Copy link

md445 commented Mar 28, 2020

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cornerRadius: CGFloat = 0.0
cell.backgroundColor = UIColor.clear
let layer: CAShapeLayer = CAShapeLayer()
let pathRef: CGMutablePath = CGMutablePath()
//dx leading an trailing margins
let bounds: CGRect = cell.bounds.insetBy(dx: 8, dy: 0)
var addLine: Bool = false

    if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.__addRoundedRect(transform: nil, rect: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius)
    } else if indexPath.row == 0 {
        pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
        pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.minY),
                       tangent2End: CGPoint(x: bounds.midX, y: bounds.minY),
                       radius: cornerRadius)
        
        pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY),
                       tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
                       radius: cornerRadius)
        pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        addLine = true
    } else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
        pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY),
                       tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY),
                       radius: cornerRadius)
        
        pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY),
                       tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
                       radius: cornerRadius)
        pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
    } else {
        pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
        pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY),
                       tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY),
                       radius: cornerRadius)
        
        pathRef.move(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY),
                       tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
                       radius: cornerRadius)
        pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        addLine = true
    }
    
    layer.path = pathRef
    layer.strokeColor = UIColor.lightGray.cgColor
    layer.lineWidth = 1.0
    layer.fillColor = UIColor.clear.cgColor
    
    if addLine == true {
        let lineLayer: CALayer = CALayer()
        let lineHeight: CGFloat = (1 / UIScreen.main.scale)
        lineLayer.frame = CGRect(x: bounds.minX, y: bounds.size.height - lineHeight, width: bounds.size.width, height: lineHeight)
        lineLayer.backgroundColor = UIColor.clear.cgColor
        layer.addSublayer(lineLayer)
    }
    
    let backgroundView: UIView = UIView(frame: bounds)
    backgroundView.layer.insertSublayer(layer, at: 0)
    backgroundView.backgroundColor = .clear
    cell.backgroundView = backgroundView

}

@jiraheta
Copy link

This worked wonders. I do want to thank you for the time you spent on this.

@bharathreddys77
Copy link

Excellent !!! that works like charm...

@DevSoft0073
Copy link

How can I use this code?

@victortumble
Copy link

victortumble commented Sep 14, 2022

this is what I was looking for but instead of using in tableview cell I ended up creating a custom UIView.

public class UIBorderedView: UIView {
    var color = UIColor.white
    var lineWidth: CGFloat = 1
    var edges = UIRectEdge() {
        didSet {
            roundInternal()
            setNeedsDisplay()
        }
    }

    private var _cornerRadiusValue: CGFloat = 20

    var cornerRadiusValue: CGFloat {
        get {
            return _cornerRadiusValue
        }
        set {
            if newValue != cornerRadiusValue {
                _cornerRadiusValue = newValue
                roundInternal()
                setNeedsDisplay()
            }
        }
    }

    private func roundInternal() {
        var corners: CACornerMask = []

        if edges.contains(.top) {
            corners.insert([.layerMinXMinYCorner, .layerMaxXMinYCorner])
        }

        if edges.contains(.bottom) {
            corners.insert([.layerMinXMaxYCorner, .layerMaxXMaxYCorner])
        }

        var radius = cornerRadiusValue
        if edges.contains(.all) {
            radius = radius / 2
        }

        round(with: radius, corners: corners)
    }

    public override func draw(_ rect: CGRect) {
        if edges.contains(.all) {
            let radius = cornerRadiusValue / 2
            let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: radius, height: radius))
            path.lineWidth = lineWidth
            color.setStroke()
            path.stroke()
            return
        }

        if edges.contains(.top) {
            let path = CGMutablePath()

            path.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))

            path.addArc(
                tangent1End: CGPoint(x: bounds.minX, y: bounds.minY),
                tangent2End: CGPoint(x: bounds.midX, y: bounds.minY),
                radius: cornerRadiusValue
            )

            path.addArc(
                tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY),
                tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
                radius: cornerRadiusValue
            )

            path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))

            let bezier = UIBezierPath(cgPath: path)
            bezier.lineWidth = lineWidth
            color.setStroke()
            bezier.stroke()
            return
        }

        if edges.contains(.bottom) {
            let path = CGMutablePath()

            path.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
            path.addArc(
                tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY),
                tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY),
                radius: cornerRadius
            )

            path.addArc(
                tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY),
                tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY),
                radius: cornerRadius
            )
            path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))

            let bezier = UIBezierPath(cgPath: path)
            bezier.lineWidth = lineWidth
            color.setStroke()
            bezier.stroke()
            return
        }

        let left = UIBezierPath()

        left.move(to: bounds.origin)
        left.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
        left.lineWidth = lineWidth
        color.setStroke()
        left.stroke()

        let right = UIBezierPath()

        right.move(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        right.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        right.lineWidth = lineWidth
        color.setStroke()
        right.stroke()
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment