UITableView 的 type 为 grouped 时内容起点向下偏移

2,504 阅读2分钟

bug 场景

我本意是用 grouped 的方式创建的 tableView, 每组有 sectionHeadersectionFooter, 设置 tableHeaderView, 由于 header 的高度不确定, 所以初始化 frame.zero, 在数据请求回来后更新 header 的高度.

但是 bug 就这么出现了, 第0组的 sectionHeader 的 y 值默认为 35, 也就是说 tableView 内容展示起点向下偏移 35, 可以看到 tableView 的背景色.

代码和效果图

代码

  • 代码比较简单, 就是一个普通的列表, 部分写法只是为了满足本示例, 与正常开发不同, 所以还请谅解, cell 点击事件模拟数据返回后更新 header 高度.

    
    import UIKit
    
    fileprivate let UITableViewCellID = "UITableViewCellID"
    
    class ViewController: UIViewController {
    
        let size = UIScreen.main.bounds.size
    
        private lazy var header: UIView = {
            let v = UIView(frame: .zero)
            v.backgroundColor = .cyan
            return v
        }()
    
        private lazy var tableView: UITableView = {
            let fRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
            let tv = UITableView(frame: fRect, style: .grouped)
            tv.backgroundColor = .blue
            tv.separatorStyle = .none
            tv.rowHeight = 40
            tv.showsVerticalScrollIndicator = false
            tv.tableHeaderView = header
            tv.delegate = self
            tv.dataSource = self
            tv.contentInsetAdjustmentBehavior = .never
            tv.register(UITableViewCell.self, forCellReuseIdentifier: UITableViewCellID)
            return tv
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.addSubview(tableView)
        }
    }
    
    extension ViewController: UITableViewDelegate, UITableViewDataSource {
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 4
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 3
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            let cell = tableView.dequeueReusableCell(withIdentifier: UITableViewCellID, for: indexPath)
    
            cell.textLabel?.text = "\(indexPath.section) 组 -- \(indexPath.row) 行"
    
            return cell
        }
    
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
            let header = UILabel(frame: .zero)
            header.backgroundColor = .red
            header.font = UIFont.systemFont(ofSize: 18);
            header.text = "\(section) 组 -- 头"
            return header
        }
    
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 50.0
        }
    
        func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
            let footer = UILabel(frame: .zero)
            footer.backgroundColor = .green
            footer.font = UIFont.systemFont(ofSize: 18);
            footer.text = "\(section) 组 -- 尾"
            return footer
        }
    
        func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
            return 50.0
        }
    
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
            header.frame.size.height = 200;
    
            tableView .reloadData()
        }
    }
    

效果图

  • 效果: image.png

  • 偏移量 image.png

解决方案

经过上网查资料 和 自己的尝试, 最终解决方案就是在 header 初始化的时候设置 frame , 起决定作用的是高度, 设置高度的绝对值大于 0.1 就可以, 亲测 -1 可以. 最终体现为两种方式.

方式一

  • 就是一些具体的数值, 如 -1, 1, 100, 根据自己的具体需求来定.

    private lazy var header: UIView = {
        let v = UIView(frame: CGRect(x: 0, y: 0, width: size.width, height: -1))
        v.backgroundColor = .cyan
        return v
    }()
    

    明显可以看出顶部一条线, 实际开发中可以设置为白色或透明色, 看上去没有异常为准.

    image.png

方式二

  • 设置高度为 CGFloat.leastNormalMagnitude(OC 对应的变量是 CGFLOAT_MIN)

    private lazy var header: UIView = {
        let v = UIView(frame: CGRect(x: 0, y: 0, width: size.width, height: CGFloat.leastNormalMagnitude))
        v.backgroundColor = .cyan
        return v
    }()
    

    这种方案比较完美, 顶部并没有看到有线条.

    image.png

更新 header 效果

  • 当点击一下 cell 时更新 header 高度为 200, 此时需要刷新列表, 否则展示会异常.

    image.png

因为我的机型有限, 所以具体情况大家具体对待, 也可能在某些情况下不合适, 所以仅供参考.
能看到这里的, 那必须要谢谢大家支持 😄😄😄