UIKit - Swift - 允许 tableHeaderView 向上滚动,但不能向下滚动

UIKit - Swift - Allow tableHeaderView to scroll up, but not down

我有一个带有导航栏和标签栏的 UIViewController。除此之外,整个屏幕由一个 UITableView 组成。

我有一个大的 tableHeaderView,它的背景颜色与导航栏相同。

当我向上拖动内容(向下滚动)时,一切看起来都很好。

但是如果我向上拖动它,导航栏和 header 视图之间就会出现丑陋的脱节。

有什么方法可以让我在向下拖动时将它固定在顶部,同时允许它在向上拖动时滚动?

1) 如果 tableview 顶部不需要的白色 space 是永久性的并且约束是正确的,这就是解决方案。 滚动视图插入自动调整如果你禁用它应该删除它

if #available(iOS 11.0, *) {
    tableView.contentInsetAdjustmentBehavior = .never
} else {
    automaticallyAdjustsScrollViewInsets = false
}

2) 如果你把它拉下来,它又恢复到正常状态。这意味着 tableview 弹跳已启用,根据 iOS 文档,这是正常行为:

如果此 属性 的值为真,则滚动视图在遇到内容边界时弹跳。弹跳在视觉上表明滚动已到达内容的边缘。如果该值为 false,则滚动会立即停止在内容边界处而不会弹跳。默认值为真。

您可以在故事板或 xib 文件中取消选中表视图的弹跳。或者你可以使用这个片段:

tableView.bounces = false
tableView.alwaysBounceVertical = false

注意: 不建议禁用滚动弹跳,因为这会让 iOS 感觉很不自然。 而且如果你想使用 pull 来刷新它也不会工作。

所以最后,如果您选择不禁用它,您将不得不更改 tableview 父级的背景颜色,这将解决它。

我希望这是有道理的!

您可以尝试创建一个视图并将其放在 tableView 后面,随着 table 视图的滚动,视图的高度会更新。

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView : UITableView = {
        let tableView = UITableView(frame: .zero, style: .plain)
        tableView.dataSource = self
        tableView.delegate = self
        return tableView
    }()

    let backView : UIView = {
        let view = UIView()
        view.backgroundColor = .red
        return view
    }()

    var backViewHeight : NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "ViewController"

        self.view.addSubview(backView)
        backView.translatesAutoresizingMaskIntoConstraints = false
        backView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
        backView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        backView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        backViewHeight = backView.heightAnchor.constraint(equalToConstant: 0)
        backViewHeight?.isActive = true

        self.view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
        tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        tableView.register(Cell.self, forCellReuseIdentifier: "cell")
        tableView.register(Header.self, forHeaderFooterViewReuseIdentifier: "header")
        tableView.backgroundColor = .clear

        self.navigationController?.navigationBar.barTintColor = .red
        self.navigationController?.navigationBar.isTranslucent = false
        self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }


    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y < 0 {
            backViewHeight?.constant = -scrollView.contentOffset.y
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        return cell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "header")
        header?.contentView.backgroundColor = .red
        let headerLabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: 100))
        headerLabel.textAlignment = .center
        headerLabel.text = "Header"
        header?.addSubview(headerLabel)
        return header
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 100
    }

    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let view = UIView()
        view.backgroundColor = .white
        return view
    }

}

class Cell: UITableViewCell {

    let label : UILabel = {
        let label = UILabel()
        label.text = "One Label"
        return label
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.backgroundColor = .clear
        setupViews()
    }

    func setupViews() {
        self.backgroundColor = .white
        self.addSubview(label)
        label.frame = self.frame
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class Header : UITableViewHeaderFooterView {


    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

如果您将此代码复制粘贴到一个空项目中,您可以查看行为。不要忘记将 ViewController 嵌入到 NavigationController 中。希望对你有帮助