Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS UITableViewCell horizontally scrolling subviews with auto layout

I'm attempting to build a table view, who's cells contain cards that are horizontally scrolled. I created a simple demo-app and have had success in implementing a version that uses Auto Layout... to a certain extent. One (I believe to be final) issue remains. The vertical sizing of the cards is bugged.

TableView:

class MultiCardTableViewController: UITableViewController {
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 12
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("CardCell", forIndexPath: indexPath) as CardCell

        //since these cells are re-used, we have to clear out the previous dynamic subviews
        for subView in cell.scrollContentView.subviews { subView.removeFromSuperview() }

        var card = NSBundle.mainBundle().loadNibNamed("CardView", owner: self, options: nil)[0] as CardView
        //Turn this off because subviews of UIScrollView use autoresizing mask by default, which conflict with Auto-Layout constraints
        card.setTranslatesAutoresizingMaskIntoConstraints(false)
        cell.scrollContentView.addSubview(card)

        var card2 = NSBundle.mainBundle().loadNibNamed("CardView", owner: self, options: nil)[0] as CardView
        //Turn this off because subviews of UIScrollView use autoresizing mask by default, which conflict with Auto-Layout constraints
        card2.setTranslatesAutoresizingMaskIntoConstraints(false)
        cell.scrollContentView.addSubview(card2)

        //Add bottom margin to the last cell (for consistency)
        //Add vertical constraints (standard margins) for each card
        var constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-[card]|", options: nil, metrics: nil, views: ["card": card])
        constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-[card2]|", options: nil, metrics: nil, views: ["card2": card2])
        //Add horizontal constraints that tie the cards together, and to the super view
        constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:|-[card]-(16)-[card2]-|", options: nil, metrics: nil, views: ["card": card, "card2": card2])
        //Add horizontal constraint that disambiguates individual card width
        constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:[card(==card2)]", options: nil, metrics: nil, views: ["card": card, "card2": card2])
        cell.scrollContentView.addConstraints(constraints)

        //Set the scrollview content horizontal size constraint to double the window width (1 window width for each card
        cell.contentWidthConstraint.constant = self.tableView.frame.width * 2

        return cell
    }
}

Cell:

class CardCell: UITableViewCell
{
    @IBOutlet weak var scrollView: UIScrollView!
    //A content view directly inside of the scroll view, constrained to super view on all sides, as well as height & width
    @IBOutlet weak var scrollContentView: UIView!
    //A reference to the width constraint for the scrollContentView
    @IBOutlet weak var contentWidthConstraint: NSLayoutConstraint!
}

CardView.xib:

CardView Nib File

Result:

Horizontal Scroll Bug

The horizontal spacing and sizing is correct, but it appears that the vertical constraints are insufficient or incorrect. I find this hard to believe because they are so simple. Each card has the vertical constraint: V:|-[card]|

I've tried adding an explicit height constraint on the cards, similar to the width, but this also doesn't produce correct results: V:[card(==card2)]

Result of explicit vertical height constraint:

Horizontal Scroll Bug 2

I've been wracking my brains for days... What am I missing?

Edit: Added github source link for the sample project

like image 927
Albert Bori Avatar asked Oct 19 '22 22:10

Albert Bori


1 Answers

Fortunately the issue was a minor typo in my code example above:

constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-[card2]|", options: nil, metrics: nil, views: ["card2": card2])

Is overwriting the previous constraints array, and should add to it instead:

constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-[card2]|", options: nil, metrics: nil, views: ["card2": card2])
like image 113
Albert Bori Avatar answered Nov 01 '22 18:11

Albert Bori