iOS UITableView 偏移刷新控件

iOS UITableView Offset Refresh Control

我有一个受超级视图限制的 UITableView。所以第一个单元格位于父视图的顶部。这意味着在 iPhone X 上,第一个单元格在凹口下流血,并进入状态栏区域。这是完全正确的。我希望 单元格在凹口下渗入状态栏区域,这就是当前的结果。

问题是,我还想在那个 table 视图上有一个刷新控件,以便用户可以通过拉动来刷新内容。但是当你在 iPhone X 上拉动刷新时,刷新控制被缺口切断。我不希望刷新控件被缺口截断。

所以基本上我想做的是将 table 视图限制在超级视图中,但将刷新控件限制在安全区域。

我看过了,Apple 似乎没有提供很多属性或方法来自定义刷新控件的行为。

我考虑过使用某种类型的自定义解决方案,但我想到的每个自定义解决方案都失去了刷新控件和 table 视图滚动等的所有预建物理特性。幕后逻辑太多了,我真的不想牺牲拉动刷新的感觉以及用户的感觉,因为它在 iOS.

中变得如此普遍

关于如何让第一个单元格在凹口下流血(限制在超级视图)但确保刷新控制不会被凹口切断(限制在安全区域)有什么想法吗?

我还在下面附上了屏幕截图,显示了单元格如何渗入状态栏,以及刷新控件如何被缺口切断。

编辑: 我还向 GitHub here 发布了一个示例项目。

但是刷新控件相关的基本代码如下。

private lazy var refreshControl = UIRefreshControl()
override func viewDidLoad() {
    super.viewDidLoad()

    refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
    tableView.refreshControl = refreshControl
}

@objc func handleRefresh() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
        self.refreshControl.endRefreshing()
    }
}

table 视图的顶部约束必须相对于上边距

解决方法很简单,您可以在viewDidLoad 中设置刷新控件的边界。使用您需要的 y 偏移值(例如 50)

  refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
  refreshControl.bounds = CGRect(x: refreshControl.bounds.origin.x,
                                 y: 50,
                                 width: refreshControl.bounds.size.width,
                                 height: refreshControl.bounds.size.height)
  tableView.refreshControl = refreshControl

更新:

您可以在刷新开始时添加内容插入,并在结束时将其带回。

  override func viewDidLoad() {
        super.viewDidLoad()


      refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
      refreshControl.bounds = CGRect(x: refreshControl.bounds.origin.x,
                                     y: -100,
                                     width: refreshControl.bounds.size.width,
                                     height: refreshControl.bounds.size.height);
      tableView.refreshControl = refreshControl
    }

    @objc func handleRefresh() {
      self.tableView.contentInset = UIEdgeInsets(top: 200, left: 0, bottom: 0, right: 0)
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
          self.refreshControl.endRefreshing()
          self.tableView.contentInset = UIEdgeInsets.zero
          self.tableView.setContentOffset(.zero, animated: true)
        }
    }

您可以享受底层福利UIScrollView。使用您的 github 示例,您可以获得所需的一切,因此如果您将其扩展为:

extension ViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y < 0 {
            topConstraint.constant = -scrollView.contentOffset.y/2
        } else {
            topConstraint.constant = 0
        }
    }
}

什么反应每次 contentOffset 开始低于 0 并使您的 tableView 移动到底部,无论何时关闭或向下滚动它都会被设置为默认值 -在你的情况下 0.

这样,您将获得与拖动相关的流畅动画 force/distance,如下所示