0

How do I add corner radius and background to both the section header and its cell together like in the iOS weather app?

enter image description here

My table view data source and delegate-

extension HomeViewController: UITableViewDataSource, UITableViewDelegate {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        10
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        1
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: HourlyForecastViewTableViewCell.identifier) else { return UITableViewCell() }
        cell.layer.backgroundColor = UIColor.blue.cgColor
        return cell
        
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        200
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return HourlyForecastHeaderView()
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 40
    }
}

Sahil Sahu
  • 63
  • 6
  • https://developer.apple.com/documentation/uikit/uitableviewstyle/uitableviewstyleinsetgrouped – Rob C Aug 06 '22 at 14:26
  • the reason i didnt go with this solution is because I am also trying to get the sticky section headers effect that the weather app has – Sahil Sahu Aug 11 '22 at 08:16

1 Answers1

0

You can tryout this below code, here I just explained how to use UIRectCorner to apply corner radius to the specific edge.enter image description here

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        2
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        5
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let kCellId = "kCellId"
        var lCell = tableView.dequeueReusableCell(withIdentifier: kCellId)
        if lCell == nil {
            lCell = UITableViewCell(style: .default, reuseIdentifier: kCellId)
            lCell?.textLabel?.text = "Row - \(indexPath.row)"
        }
        lCell?.backgroundColor = .orange
        return lCell!
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let kHeaderId = "kHeaderId"
        var header = tableView.dequeueReusableHeaderFooterView(withIdentifier: kHeaderId)
        if header == nil {
            header = HeaderView(reuseIdentifier: kHeaderId)
            header?.frame = CGRect(origin: .zero, size: CGSize(width: tableView.bounds.size.width, height: 35))
            header?.tintColor = .orange
            
            let titleLabel = UILabel()
            titleLabel.text = "Section - \(section)"
            titleLabel.sizeToFit()
            titleLabel.frame = CGRect(origin: CGPoint(x: 20, y: 0), size: CGSize(width: tableView.bounds.size.width-20, height: 35))
            header?.addSubview(titleLabel)
        }
        return header
    }
    
    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        view.applyCorners(to: [.topLeft, .topRight], with: view.bounds)
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let isLastCell = tableView.numberOfRows(inSection: indexPath.section)-1 == indexPath.row
        if isLastCell {
            cell.applyCorners(to: [.bottomLeft, .bottomRight], with: cell.bounds)
        }else{
            cell.noCorners()
        }

    }
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        50
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        35
    }
}

class HeaderView: UITableViewHeaderFooterView {
    
}


extension UIView {
    func noCorners() {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
        let shape = CAShapeLayer()
        shape.path = path.cgPath
        layer.mask = shape
    }
    
    func applyCorners(to: UIRectCorner, with rect: CGRect) {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: to, cornerRadii: CGSize(width: 10, height: 10))
        let shape = CAShapeLayer()
        shape.path = path.cgPath
        layer.mask = shape
    }
}
Jayachandra A
  • 1,335
  • 1
  • 10
  • 21
  • Small problem with this- when u scroll and you reach the end of the cell, you can clearly see the sections bottom left and bottom right dont have any corner radius – Sahil Sahu Aug 13 '22 at 07:38
  • Since, I just have given sample for applying top corners for header and bottom corners for last cell of section, so That you have to apply bottom corner for sections where it is missing. – Jayachandra A Aug 16 '22 at 06:29