Home > database >  The difference between UITableView HeaderView and UITableViewCell when using UIBezierPath
The difference between UITableView HeaderView and UITableViewCell when using UIBezierPath

Time:08-03

enter image description here

class CornerCell: UITableViewCell {
    
    @IBOutlet weak var exLabel: UILabel!
    
    private var borderLayer = CAShapeLayer()
    private var myType: RoundedTableViewCellType = .middle
    
    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            let inset: CGFloat = 20
            var frame = newValue
            frame.origin.x  = inset
            frame.size.width -= 2 * inset
            super.frame = frame
        }
    }
    
    var borderColor: UIColor = .clear {
        didSet {
            borderLayer.strokeColor = borderColor.cgColor
        }
    }
    
    var borderWidth: CGFloat = 0.0 {
        didSet {
            borderLayer.lineWidth = borderWidth
        }
    }
    
    var radius: CGFloat = 6.0 {
        didSet {
            type = myType
        }
    }
    
    var type: RoundedTableViewCellType = .middle {
        didSet {
            myType = type
            switch type {
            case .first:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
            case .last:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
            case .single:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMinYCorner]
            case .middle:
                layer.cornerRadius = 0
                layer.maskedCorners = []
            }
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let r = radius
        var bPath = UIBezierPath()
        
        let ptTopLeft = CGPoint(x: 0.0, y: 0.0)
        let ptTopRight = CGPoint(x: bounds.width, y: 0.0)
        let ptBotRight = CGPoint(x: bounds.width, y: bounds.height)
        let ptBotLeft = CGPoint(x: 0.0, y: bounds.height)
        
        switch type {
        case .first:
            bPath.move(to: ptBotLeft)
            bPath.addLine(to: CGPoint(x: ptTopLeft.x, y: ptTopLeft.y   r))

            bPath.addQuadCurve(to: CGPoint(x: ptTopLeft.x   r, y: ptTopLeft.y),
                               controlPoint: ptTopLeft)

            bPath.addLine(to: CGPoint(x: ptTopRight.x - r, y: ptTopRight.y))

            bPath.addQuadCurve(to: CGPoint(x: ptTopRight.x, y: ptTopRight.y   r),
                               controlPoint: ptTopRight)

            bPath.addLine(to: CGPoint(x: ptBotRight.x, y: ptBotRight.y))

        case .last:
            bPath.move(to: ptTopLeft)
            
            bPath.addLine(to: CGPoint(x: ptBotLeft.x, y: ptBotLeft.y - r))
            bPath.addQuadCurve(to: CGPoint(x: ptBotLeft.x   r, y: ptBotLeft.y), controlPoint: ptBotLeft)
            
            bPath.addLine(to: CGPoint(x: ptBotRight.x - r, y: ptBotRight.y))
            bPath.addQuadCurve(to: CGPoint(x: ptBotRight.x, y: ptBotRight.y - r), controlPoint: ptBotRight)
            
            bPath.addLine(to: CGPoint(x: ptTopRight.x, y: ptTopRight.y))
        case .single:
            bPath = UIBezierPath(roundedRect: bounds, cornerRadius: r)

        case .middle:
            bPath.move(to: ptTopLeft)
            bPath.addLine(to: ptBotLeft)
            bPath.addLine(to: ptBotRight)
            bPath.addLine(to: ptTopRight)
        }
        
        borderLayer.path = bPath.cgPath
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        commonInit()
    }
    
    func commonInit() {
        layer.addSublayer(borderLayer)

        borderLayer.fillColor = UIColor.clear.cgColor

        // default values
        borderColor = .black
        borderWidth = 1.0
    }
}
class CustomHeaderView: UITableViewHeaderFooterView {

    @IBOutlet weak var titleLabel: UILabel!
    
    @IBOutlet weak var plusButton: UIButton!
    
    private var borderLayer = CAShapeLayer()
    private var myType: RoundedTableViewCellType = .middle
    
    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            let inset: CGFloat = 20
            var frame = newValue
            frame.origin.x  = inset
            frame.size.width -= 2 * inset
            super.frame = frame
        }
    }
    
    var borderColor: UIColor = .clear {
        didSet {
            borderLayer.strokeColor = borderColor.cgColor
        }
    }
    
    var borderWidth: CGFloat = 0.0 {
        didSet {
            borderLayer.lineWidth = borderWidth
        }
    }
    
    var radius: CGFloat = 6.0 {
        didSet {
            type = myType
        }
    }
    
    var type: RoundedTableViewCellType = .middle {
        didSet {
            myType = type
            switch type {
            case .first:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
            case .last:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
            case .single:
                layer.cornerRadius = radius
                layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMinYCorner]
            case .middle:
                layer.cornerRadius = 0
                layer.maskedCorners = []
            }
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let r = radius
        var bPath = UIBezierPath()
        
        let ptTopLeft = CGPoint(x: 0.0, y: 0.0)
        let ptTopRight = CGPoint(x: bounds.width, y: 0.0)
        let ptBotRight = CGPoint(x: bounds.width, y: bounds.height)
        let ptBotLeft = CGPoint(x: 0.0, y: bounds.height)
        
        switch type {
        case .first:
            bPath.move(to: ptBotLeft)
            bPath.addLine(to: CGPoint(x: ptTopLeft.x, y: ptTopLeft.y   r))

            bPath.addQuadCurve(to: CGPoint(x: ptTopLeft.x   r, y: ptTopLeft.y),
                               controlPoint: ptTopLeft)

            bPath.addLine(to: CGPoint(x: ptTopRight.x - r, y: ptTopRight.y))

            bPath.addQuadCurve(to: CGPoint(x: ptTopRight.x, y: ptTopRight.y   r),
                               controlPoint: ptTopRight)

            bPath.addLine(to: CGPoint(x: ptBotRight.x, y: ptBotRight.y))

        case .last:
            bPath = UIBezierPath(roundedRect: bounds,
                                 byRoundingCorners: [.bottomLeft, .bottomRight],
                                 cornerRadii: CGSize(width: r, height: r))

        case .single:
            bPath = UIBezierPath(roundedRect: bounds, cornerRadius: r)

        case .middle:
            bPath.move(to: ptTopLeft)
            bPath.addLine(to: ptBotLeft)
            bPath.addLine(to: ptBotRight)
            bPath.addLine(to: ptTopRight)
        }
        
        borderLayer.path = bPath.cgPath
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        commonInit()
    }
    
    func commonInit() {
        layer.addSublayer(borderLayer)

        borderLayer.fillColor = UIColor.clear.cgColor

        // default values
        borderColor = .black
        borderWidth = 1.0
    }
}

I used same code, but headerView borderWidth is thicker than cell. (headerView's type is 'first' & cell's type is 'middle'and 'last')

I don't know why this result was.

I want to draw same borderWidth.

CodePudding user response:

Borders are drawn on "center lines."

Suppose you used a borderWidth of 8 ... you will get 4-points inside the frame and 4-points outside the frame.

By default, a UITableViewCell has .clipsToBounds = true, but a UITableViewHeaderFooterView has .clipsToBounds = false.

So, the outside part of the border is visible on your header view.

You can fix this by setting .clipsToBounds to the same value on both classes. Try it with true, then try it with false, and see which you prefer.

  • Related