BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

Getting UIScrollView to work

Forums > Swift

I'm working on a settings page for an app, and one of the things that I'm looking to do is have a table with a couple of selectable options, some intro text explaining everything at the top, and some additional controls beneath. Understandng that different screen heights can cause some items to be clipped, I'm trying to put all of this into a UIScrollView. The results so far have been...unintuitive, to say the least.

Here's the code for my view controller with the embedded UIScrollView:

class ScrollViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate {
    @IBOutlet var scrollView: UIScrollView!
    @IBOutlet var tableView: UITableView!
    @IBOutlet var topView: UIView! // Placeholder, intended to represent the explanatory text above the table
    @IBOutlet var bottomView: UIView! // Placeholder, intended to represent the additional controls below the table

    @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint! // Used to dynamically resize the table

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewDidLayoutSubviews() {
    // Dynamically resize the table to fit the number of cells
    // Scrolling is turned off on the table in InterfaceBuilder
        tableView.frame.size = tableView.contentSize
        tableViewHeightConstraint.constant = tableView.frame.height
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20 // Right now we just want enough rows to guarantee the need to scroll
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell? {
            cell.textLabel?.text = "Cell content"
            tableView.sizeToFit()
            return cell
        }

        return UITableViewCell()
    }

    /// UIScrollViewDelegate
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    // Disabling horizontal scrolling
        scrollView.contentOffset.x = 0.0

        print(scrollView.contentOffset.y)
    }
}

What I'm currently seeing is that topView loads in its proper place, and tableView appears at the specified distance below it per the constraints, with cells running off the bottom of the screen. So far, so good.

Horizontal scrolling is frozen out completely. Good.

When I try to scroll vertically, however, is where it gets weird.

The content itself doesn't move. The vertical scroll bar, however, starts at the screen height and continues to shrink more and more as I endlessly scroll down. The console output shows that the Y index is being remembered and keeps going up well into the tens of thousands if I keep going—yet the content itself never actually gets scrolled. It's as if it thinks the view is ever-growing, and the visible part of the screen merely represents a smaller proportion of the content.

Before I froze out the horizontal scrolling it had no qualms about auto-updating the view and showing things sliding left and right (indeed, it wouldn't scroll vertically at all, near as I could tell). As such, especially since the console shows that contentOffset is updating automatically, I'm not really sure what else (if anything) I should be setting that isn't already being set.

Does anyone have any insights into how to get it to scroll vertically, and to be aware of the vertical content size so that it doesn't act like it can scroll infinitely (as is the current behavior)?

Thanks!

1      

Hi. I don't understand why are you combining TableView and ScrollView. TableView is perfectly capable of scrolling (it uses scroll view under the hood). I think you are making this more complex than they need to be :-) What about getting rid of the scroll view?

1      

Hi, Filip! The reason why I'm not using the scroll view that comes with the UITableView is twofold:

1) The table view isn't the entire view—I've got material I want to put above and below it. Kind of like how in a lot of the pages of the Settings app you'll see sections of table view cells broken up by other content.

2) I've been meaning to figure out how to actually set up and use UIScrollView for a while so that I can design UIs that are longer than a screen height tall.

If it'll help with envisioning the scenario, replace the table view with a really tall image view. Still need it to scroll down to see the rest of the content.

1      

In that case, I think you should use table view header and footer views (not section headers, but header for whole table view). Or in any case you can always have multiple types of cells... The Settings in iOS is almost surely just TableView or CollectionView.

I would really build the screen entirely out of these two components, it is standard approach and what you learn can be then used elsewhere.

1      

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.