Warpzit Warpzit - 6 months ago 20
iOS Question

How to get contentview inside UIScrollView to fill parent with autolayout

So I have a working UIScrollView with a content view that can scroll horizontally no problems there. I've followed all online resources I've could find and everything related to scrolling works... My problem is that the content that is put inside the contentview does not fill to the UIScrollViews bottom. It's like the scrollbar takes up the bottom 5-10 pixels making it impossible for the content to stretch there.

At the attached example image it can be seen that the text doesn't align along whole the bar, all items are added in same fashion, the only different is those inside the small scroll area has the UIScrollView as parent. The frustrating thing is this was not an issue if I set the frame and content area instead of using autolayout constraints.

Example of issue

Everything is in code (except the out most parent which has a fixed height constraint of 50 and margin of 0 to left and right)

Constraint for Scrollview and content view:

//
// scroll constraint
//
barScrollView.translatesAutoresizingMaskIntoConstraints = false

// left constraint
let leftSideConstraint = NSLayoutConstraint(item: barScrollView, attribute: .Left, relatedBy: .Equal, toItem: menuBtn, attribute: .Right, multiplier: 1.0, constant: 0)
self.addConstraint(leftSideConstraint)

// top constraint
let topSideConstraint = NSLayoutConstraint(item: barScrollView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
self.addConstraint(topSideConstraint)

// bottom constraint
let botSideConstraint = NSLayoutConstraint(item: barScrollView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0)
self.addConstraint(botSideConstraint)

// right side constraint
let rightSideConstraint = NSLayoutConstraint(item: barScrollView, attribute: .Right, relatedBy: .Equal, toItem: collapseBtn, attribute: .Left, multiplier: 1.0, constant: 0)
self.addConstraint(rightSideConstraint)


//
// scroll content constraint
//
barScrollContentView.translatesAutoresizingMaskIntoConstraints = false

// left constraint
let contentLeftSideConstraint = NSLayoutConstraint(item: barScrollContentView, attribute: .Left, relatedBy: .Equal, toItem: barScrollView, attribute: .Left, multiplier: 1.0, constant: 0)
barScrollView.addConstraint(contentLeftSideConstraint)

// top constraint
let contentTopSideConstraint = NSLayoutConstraint(item: barScrollContentView, attribute: .Top, relatedBy: .Equal, toItem: barScrollView, attribute: .Top, multiplier: 1.0, constant: 0)
barScrollView.addConstraint(contentTopSideConstraint)

// bottom constraint
let contentBotSideConstraint = NSLayoutConstraint(item: barScrollContentView, attribute: .Bottom, relatedBy: .Equal, toItem: barScrollView, attribute: .Bottom, multiplier: 1.0, constant: 0)
barScrollView.addConstraint(contentBotSideConstraint)

// right side constraint
let contentRightSideConstraint = NSLayoutConstraint(item: barScrollContentView, attribute: .Right, relatedBy: .Equal, toItem: barScrollView, attribute: .Right, multiplier: 1.0, constant: 0)
barScrollView.addConstraint(contentRightSideConstraint)


And all items inside is added like following:

/**
Add constraints to an item used in the bar

- parameters:
- newElement: The new element that is added
- leftElement: The element to the left of the new element
- parent: The parent view the constraint is added to
- width: The size of the new element
- isFirstItem: Boolean indicating if this item is the furtest item to the left side
in the current container
*/
func addConstraintToItem(newElement: UIView, leftElement: UIView, parent: UIView, width: CGFloat, isFirstItem: Bool) {
newElement.translatesAutoresizingMaskIntoConstraints = false

// Width constraint
let widthConstraint = NSLayoutConstraint(item: newElement, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: width)
parent.addConstraint(widthConstraint)

// Height constraint
//let heightConstraint = NSLayoutConstraint(item: newElement, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.frame.height)
//parent.addConstraint(heightConstraint)

// left constraint
var leftSideConstraint: NSLayoutConstraint

if isFirstItem {
leftSideConstraint = NSLayoutConstraint(item: newElement, attribute: .Left, relatedBy: .Equal, toItem: leftElement, attribute: .Left, multiplier: 1.0, constant: 0)

} else {
leftSideConstraint = NSLayoutConstraint(item: newElement, attribute: .Left, relatedBy: .Equal, toItem: leftElement, attribute: .Right, multiplier: 1.0, constant: 0)
}
parent.addConstraint(leftSideConstraint)

// top constraint
let topSideConstraint = NSLayoutConstraint(item: newElement, attribute: .Top, relatedBy: .Equal, toItem: parent, attribute: .Top, multiplier: 1.0, constant: 0)
parent.addConstraint(topSideConstraint)

// bot constraint
let botSideConstraint = NSLayoutConstraint(item: newElement, attribute: .Bottom, relatedBy: .Equal, toItem: parent, attribute: .Bottom, multiplier: 1.0, constant: 0)
parent.addConstraint(botSideConstraint)
}

Answer

Try by adding two more constraint to barScrollContentView : Center Y (Vertically in container) and fixed width. This may solve your problem i think.