Jon Cox Jon Cox - 6 months ago 138
Swift Question

Setting a minimum content size on a UITableView

I have a view at the top of a view controller, and a tableview underneath it.

I've made it such that as the tableview is scrolled up the top view scrolls up too, up to a maximum amount, of lets say 50 points.

The tableview also has a top inset of 50:

tableView = UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0)


... so that it's cells start below the top view.

And in the scrollview delegate there is some code along the lines of:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
let scrollViewYOffset = ...
topViewHeightConstraint.constant = max(minTopViewHeight, minTopViewHeight - scrollViewYOffset)
}


This ensures as the user drags down on the tableview the top view 'sticks' to it, and is also pushed up when the user pushes the table view up.

I've drawn this picture to better describe what the Storyboard looks like:

enter image description here

So far so good. When there are a lot of cells and the user scrolls the table view up, the top view remains at it's minimum height nicely.

But if you are scrolled up - so the top view is at it's minimum - then the number of cells are reduced, the top view pings back down to it's maximum height.

This is because the actual content size of the tableview has dropped below its bounds height, and so as a scrollview it brings the top of the content to the top of the scrollview again (plus the 50 point top inset of course).




I would like to be able to scroll the tableview up, so the top view remains at its minimum height, regardless of the number of cells it contains - i.e. regardless of it's content size.

Can anyone think of a clever way to set a minimum content size on the table view?

(So far I've tried messing around with the footer, having a cell at the bottom that is essentially a spacer - this messes up the tableview's logic and some reordering code I have in there. I've attempted to coerce the offers etc. to my will, but haven't quite worked out how to achieve this.)

I would greatly appreciate some UI genius to point me in the right direction :) Thank you.

UPDATE:

Thank you for all the answers and comments.

After trying various types of footer and header views, tweaking constraints & layout priorities on scroll, adding spacer cells, putting the tableview inside a scrollview, etc. - it finally occurred to me I was making this more complicated than I needed to, and should just update the cause of the problem on the scrollViewDidScroll, the
contentInset
value.

See the answer below for a code example that achieves the behaviour I was looking for.

Answer Source

As the contentInset is what is causing the tableview to ping back to the wrong point, I simply needed to adjust the content inset as the tableview was scrolled up/down.

Here is some example code of what I did:

let maxPointsTopViewCanMoveUp: CGFloat = 50

let topInset = abs(min(max(-maxPointsTopViewCanMoveUp, scrollView.contentOffset.y), 0))
scrollView.contentInset = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)
scrollView.scrollIndicatorInsets = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)

let amountToMoveTopViewUp = maxPointsTopViewCanMoveUp - topInset
topViewToSuperviewTopConstraint.constant = amountToMoveTopViewUp

This is called from the scrollViewDidScroll of the tableview.

It means that when there are too few cells in the tableview to fill the content, the top the tableview sticks in the place it had been scrolled up to (i.e. the amount it had pushed up the top view).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download