iOS UITableView Offset Refresh Control

You can take benefits for underlaying UIScrollView. With your github example you got everything you need there, so if you extend it with:

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

What react every time contentOffset starts to be lower than 0 and make your tableView moved to bottom and whenever is closed or scrolling down it will be set to default value - in your case 0.

That way you will endup with smooth animation related to dragging force/distance as below

enter image description here


The solution is easy, you can set bounds of your refresh control in viewDidLoad. Use y offset value you need (50 for example)

  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

And now it looks like this

UPDATE:

You can add content inset at refresh beginning, and bring it back at the end.

  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)
        }
    }