UIScrollView with dynamically created UIButtons not Scrolling - swift

I am using Xcode 6.2 and Swift. I have set up with storyboard a UIScrollView which I fill with varying numbers of programmatically created buttons. Each button varies in height due to the data contained. All of this usually creates a list longer than a single screen thus requiring scroll ability. As I loop and create each button I also adjust the height of the button to meet the needs of the content. So, in short varying numbers of buttons of varying size. I am able to set the height for the scrollView by summing up each buttons height during creation. Suddenly I cannot scroll the buttons anymore. I have tried many of the suggestions made on this site for other related questions but none fix my problem.
some code:
// Add constraints depending on what number button it is
let heightConstraint:NSLayoutConstraint = NSLayoutConstraint(item: codeData, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: CGFloat(buttonHeight))
codeData.addConstraint(heightConstraint)
let leftMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: codeData, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollviewContentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 900)
let rightMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: codeData, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollviewContentView, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 900)
let topMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: codeData, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollviewContentView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: CGFloat(sumOfButtonTops))
self.scrollviewContentView.addConstraints([leftMarginConstraint,rightMarginConstraint, topMarginConstraint])
let contentViewHeight:NSLayoutConstraint = NSLayoutConstraint(item: self.scrollviewContentView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.codeButtonArray[0], attribute: NSLayoutAttribute.Height, multiplier: 1, constant: CGFloat(sumOfButtonTops + 30))

Related

Adding constraints to in image within scrollView breaks panning

Using swift 3.0 iOS 10.x
Need an image within a scrollView to stick to the sides when I go from landscape to portrait and put this NSLayout rules into place.
let imageViewRight = (NSLayoutConstraint(item: self.image2P, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1.0, constant: 0))
let imageViewLeft = (NSLayoutConstraint(item: self.image2P, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1.0, constant: 0))
let imageViewTop = NSLayoutConstraint(item: self.image2P, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0)
let imageViewBot = NSLayoutConstraint(item: self.image2P, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant:0)
self.view.addConstraints([imageViewBot,imageViewTop,imageViewRight,imageViewLeft])
NSLayoutConstraint.activate([imageViewBot,imageViewTop,imageViewRight,imageViewLeft])
They work, but of course if I zoom into the image I find they break panning.
I thought I might be able to get around it by activating and deactiving them, but even if I simply add them it breaks... is this correct behaviour?

Properly captioning aspect fit images

I am looking for the proper way to add a caption to the top and bottom of any image in an imageview set to aspect fit. Seems simple enough, but the textbox doesnt seem to move most of the time and ends up in the center other times. Here is an example of a formula I tried for the top caption.
mainTextBox.center.y = mainImageView.center.y + (mainImageView.image!.size.height / 2) - (mainTextBox.frame.size.height / 2)
Updated with help from Vandan Patel:
I have also tried manually setting constraints manually buy receive an error
let titleLabelWidth = NSLayoutConstraint(item: mainTextBox, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Width, multiplier: 0.9, constant: 0)
let titleLabelCenterX = NSLayoutConstraint(item: mainTextBox, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
let titleLabelCenterY = NSLayoutConstraint(item: mainTextBox, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
let titleLabelHeight = NSLayoutConstraint(item: mainTextBox, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 0.9, constant: 0)
mainTextBox.addConstraints([titleLabelWidth, titleLabelCenterX, titleLabelCenterY, titleLabelHeight])
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:mult‌​iplier:constant:]: A multiplier of 0 or a nil second item together with a location for the first attribute creates an illegal constraint of a location equal to a constant. Location attributes must be specified in pairs'
Are you looking for something like this?
//title-Label Constraints
let titleLabelWidth = NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: blurEffectView, attribute: .width, multiplier: 0.9, constant: 0)
let titleLabelCenterX = NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: blurEffectView, attribute: .centerX, multiplier: 1, constant: 0)
let titleLabelCenterY = NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: blurEffectView, attribute: .centerY, multiplier: 1, constant: 0)
let titleLabelHeight = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: blurEffectView, attribute: .height, multiplier: 0.9, constant: 0)
self.addConstraints([titleLabelWidth, titleLabelCenterX, titleLabelCenterY, titleLabelHeight])

How to center multiple elements inside UIView

I'm trying to center multiple elements (labels and buttons) inside UIView (or UIStackView). I tried adding elements to UIStackView with Center Alignment and Distribution Fill and Spacing 10, but my elements keeps getting positioned from the left side. I tried changing centers. Still no luck.
What i'm trying to achieve:
[-------label--button-------] With 2 elements.
[--label--button--button--] With 3 elements.
Is there any way of achieving this without using spacers. Theoretically I maybe could use constrains, but i'm not sure it's a good idea because of changing number of elements.
let simpleView = UIView()
simpleView.addSubview(text)
simpleView.addSubview(button)
let leftLeading = NSLayoutConstraint(item: text, attribute:
.LeadingMargin, relatedBy: .Equal, toItem: simpleView,
attribute: .LeadingMargin, multiplier: 1.0,
constant: 10)
let leftLeading2 = NSLayoutConstraint(item: button, attribute:
.LeadingMargin, relatedBy: .Equal, toItem: simpleView,
attribute: .LeadingMargin, multiplier: 1.0,
constant: 10)
simpleView.addConstraint(leftLeading)
simpleView.addConstraint(leftLeading2)
simpleView.translatesAutoresizingMaskIntoConstraints = false
simpleView.sizeToFit()
newView.addSubview(simpleView)
let horizontalConstraint = NSLayoutConstraint(item: simpleView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: newView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
newView.addConstraint(horizontalConstraint)
let verticalConstraint = NSLayoutConstraint(item: simpleView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: newView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
newView.addConstraint(verticalConstraint)
I must be doing something wrong because this is what I get (newView is red, button is blue, text label is missing) :
Create a view, center the view where you need to. Then inside that view you can insert each element and give each one a programatic NSLayoutConstraint that has a .Leading of 5 or whatever spacing you want between elements.
VIEW[ELEMENT ELEMENT ELEMENT]
The number will not matter. Look into NSLayoutConstraints and make sure you use view.addConstraints.

How to add equal width and equal height constraints programmatically in swift?

Could anyone help me I have this simple view that is very simple to do if I'm using story board but all of my UILabel is based on somewhere(API) that is why I need to create my view programmatically.
this is the view I would like to achieved
what I accomplished at the moment are pinning the top label in its position and adding leading space on label 1, 2, & 3
basically what i need are:
pin the label 1 to the top label
pin the label 3 to bottom
add vertical spaces to label 1,2,3
have equal width and height constraint in label 1,2 ,3
this is my code so far.
private func addTopConstraint(from:AnyObject,to:AnyObject,cons:CGFloat){
let topConstraint = NSLayoutConstraint(item: from, attribute: .Top, relatedBy: .Equal, toItem: to, attribute: .Bottom, multiplier: 1.0, constant: cons)
self.view.addConstraint(topConstraint)
}
private func addVerticalSpace(from:AnyObject,to:AnyObject,cons:CGFloat){
let verticalSpace = NSLayoutConstraint(item: from, attribute: .Bottom, relatedBy: .Equal, toItem: to, attribute: .Bottom, multiplier: 1.0, constant: cons)
self.view.addConstraint(verticalSpace)
}
private func addLeadingSpace(from:AnyObject,to:AnyObject,cons:CGFloat){
let leadingSpace = NSLayoutConstraint(item: from, attribute: .Leading, relatedBy: .Equal, toItem: to, attribute: .Leading, multiplier: 1.0, constant: cons)
self.view.addConstraint(leadingSpace)
}
private func sameWidthAndHeight (from:AnyObject,to:AnyObject){
let width = NSLayoutConstraint(item: from, attribute: .Width, relatedBy: .Equal, toItem: to, attribute: .Width, multiplier: 1.0, constant: 0)
let height = NSLayoutConstraint(item: from, attribute: .Height, relatedBy: .Equal, toItem: to, attribute: .Height, multiplier: 1.0, constant: 0)
self.view.addConstraint(width)
self.view.addConstraint(height)
}
but the sameWidthAndHeight and addVerticalSpace function fails
maybe it something to do with content hugging and priorities too, I'm not that sure since we're used to do this in storyboard.
could anyone share a thought? Thanks in advance

Adding constraints programmatically in UIView with UITextView

I added constraints programmatically in my UITextView, but trailing and bottom constraints are not working correctly. others work fine.
I think UITextView frame size is not correct.
I just want to add margin in my UITextView programmatically.
My code is
let textView = UITextView()
self.view.addSubview(textView)
var constraints = [NSLayoutConstraint]()
constraintTop = NSLayoutConstraint(item: textView,
attribute: NSLayoutAttribute.Top,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Top,
multiplier: 1.0,
constant: 10)
constraints.append(constraintTop)
constraintBottom = NSLayoutConstraint(item: textView,
attribute: NSLayoutAttribute.Bottom,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Bottom,
multiplier: 1.0,
constant: 10)
constraints.append(constraintBottom)
constraintLeft = NSLayoutConstraint(item: textView,
attribute: NSLayoutAttribute.Leading,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Leading,
multiplier: 1.0,
constant: 10)
constraints.append(constraintLeft)
constraintRight = NSLayoutConstraint(item: textView,
attribute: NSLayoutAttribute.Trailing,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Trailing,
multiplier: 1.0,
constant: 10)
constraints.append(constraintRight)
self.view.addConstraints(constraints)
You can fix this in one of two ways:
Change the constant to -10 for your bottom and trailing constraints.
or
Switch the order of the item: and toItem: values in the bottom and trailing constraints. That is, make item: self.view and toItem: textView for the bottom and trailing constraints. This is how it is done if you set the constraints in the StoryBoard.