Issue with conflicting constraints - swift

I am not sure what I am missing here, I have been going at this for hours, looks at constant tutorials, and I am still getting an issue with conflicting constraints. Basically I have a button, and on this button I want to add a new view that is center to the button and the same size. When I go to apply the constraints, it is telling me that there are conflicting constraints, and I am just not understanding what can be conflicting here.
//Create a new view
let selectBorderView = UIView();
//Guarantee there are no constraints attached to it
NSLayoutConstraint.deactivateConstraints(selectBorderView.constraints);
//Add the new view to the button
sender.addSubview(selectBorderView);
//Create constraint selectBorderView.width = button.width
let constraintEW = NSLayoutConstraint(item: selectBorderView, attribute: .Width, relatedBy: .Equal, toItem: selectBorderView.superview, attribute: .Width, multiplier: 1, constant: 0);
//Create constraint selectBorderView.height = button.height
let constraintEH = NSLayoutConstraint(item: selectBorderView, attribute: .Height, relatedBy: .Equal, toItem: selectBorderView.superview, attribute: .Height, multiplier: 1, constant: 0);
//Create constraint selectBorderView.centerX = button.centerX
let constraintCX = NSLayoutConstraint(item: selectBorderView, attribute: .CenterX, relatedBy: .Equal, toItem: selectBorderView.superview!, attribute: .CenterX, multiplier: 1, constant: 0);
//Create constraint selectBorderView.centerY = button.centerY
let constraintCY = NSLayoutConstraint(item: selectBorderView, attribute: .CenterY, relatedBy: .Equal, toItem: selectBorderView.superview, attribute: .CenterY, multiplier: 1, constant: 0);
//add the constraints to the button
selectBorderView.superview!.addConstraint(constraintEW);
selectBorderView.superview!.addConstraint(constraintEH);
selectBorderView.superview!.addConstraint(constraintCX);
selectBorderView.superview!.addConstraint(constraintCY);

You are likely seeing an error message that says something like:
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
If you see that warning, you should set translatesAutoresizingMaskIntoConstraints to false:
selectBorderView.translatesAutoresizingMaskIntoConstraints = false

Related

How we set constraint for adding subview

I want to add view on my View, but they are not set well this width stretch. I am new to iOS. Any help would be appreciated. This is what I get when I try to do what I want, can someone help to fix this:
openView.translatesAutoresizingMaskIntoConstraints = false
let topConstraint = NSLayoutConstraint(item: openView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: openView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: openView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: openView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)
self.view.addSubview(openView)
openView.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
openView.layoutIfNeeded()
In your xcode open main.Storyboard --> Open your viewController -->Add UIView --> Make your view frame like you want --> And add constraints
Ex: If you want width=600 & height=600, set frame like you want and then assign constraints.
.Refer linked image for reference
Here you are setting subview's frame as the initial frame of controller view. ie, the controller's view will be fully covered by subview.
If you want to add constraints,
1) Take the storyboard or xib.
2) Tap on the UI element.
3) Tap on the constraints button as shown in image.
4) Set the values from each border.
You can also set height, width such like parameters. The whole need is the system should be able to interpret the accurate position from the constraints.

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.

Programmatically creating constraints bound to view controller margins

I'm trying to make a view that will act as a sort of "panel", attached to the right side of the view controller.
That is, it is bound to the trailing, top, and bottom margins of the parent view controller, with a static width of 300
However, I just can't seem to get it right, I'm either breaking a constraint or doing something xcode tells me is illegal.
What am I doing wrong?
Here is the code in the controller
let myView = UIView()
view.backgroundColor = UIColor.redColor()
self.view.addSubview(view)
let topConstraint = NSLayoutConstraint(item: myView,
attribute: .Top,
relatedBy: .Equal,
toItem: self.topLayoutGuide,
attribute: .Bottom,
multiplier: 1,
constant: 0)
let trailingConstraint = NSLayoutConstraint(item: self.view,
attribute: .TrailingMargin,
relatedBy: .Equal,
toItem: myView,
attribute: .Trailing,
multiplier: 1,
constant: 0)
let bottomConstraint = NSLayoutConstraint(item: self.bottomLayoutGuide,
attribute: .Top,
relatedBy: .Equal,
toItem: myView,
attribute: .Bottom,
multiplier: 1,
constant: 0)
let widthConstraint = NSLayoutConstraint(item: myView,
attribute: .Width,
relatedBy: .Equal,
toItem: nil,
attribute: .NotAnAttribute,
multiplier: 1,
constant: 300)
self.view.addConstraints([trailingConstraint])
view.addConstraints([topConstraint, bottomConstraint, widthConstraint])
Actually the problem in your code is that you did not set the translatesAutoresizingMaskIntoConstraints of myview to false, whenever you want to use auto-layout constraints then you have to set translatesAutoresizingMaskIntoConstraints of a view to false.
Another Problem is that you do not add myview on self.view I have updated your code and Its working fine According your constraints.
Put below code in your ViewController .
let myView = UIView()
myView.backgroundColor = UIColor.redColor()
self.view.addSubview(myView)
myView.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Bottom, relatedBy: .Equal, toItem: self.bottomLayoutGuide, attribute:.Top, multiplier: 1, constant: 20))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 300))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .TrailingMargin, relatedBy: .Equal, toItem: view, attribute: .TrailingMargin, multiplier: 1, constant: 0))
In your example code above, it seems like you are mixing up view and myView in a few places. In any event, widthConstraint should be added to myView and topConstraint, trailingConstraint, and bottomConstraint should be added to self.view. The reason for this is constraints must be added to the closest superview ancestor that lays out both views involved in the constraint. In the case where you are constraining a child view attribute to an attribute on its parent view, the constraint must be added to the parent view, since it lays out both itself and the child view. If you have a constraint between two sibling views, the constraint would be added to their parent view, since it is the closest ancestor that lays out both the views involved.
If you're able to target iOS 9.0 and above, it's much cleaner and easier to use the new NSLayoutAnchor and NSLayoutDimension API for creating these kinds of constraints. It also provides strict type checking and the compiler can verify correctness. With these new APIs, your example code would simply become:
let myView = UIView()
myView.backgroundColor = UIColor.redColor()
self.view.addSubview(myView)
let margins = self.view.layoutMarginsGuide
myView.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor).active = true
myView.topAnchor.constraintEqualToAnchor(margins.topAnchor).active = true
myView.bottomAnchor.constraintEqualToAnchor(margins.bottomAnchor).active = true
myView.widthAnchor.constraintEqualToConstant(300.0).active = true
No need to explicitly add the constraints to the right view, etc. You can read more about this method of creating constraints here:
https://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutAnchor_ClassReference/
and here:
https://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutDimension_ClassReference/
There seems to be some ambiguity in your code, you are creating a UIView as myView but adding view to self.view and even constraint also to view itself. So correct your code and replace view with myView.
Secondly setTranslayesAutoresizingMaskIntoConstraints to false.
Then add all the constraints to self.view. This should solve your problem.
myView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addConstraints([trailingConstraint, bottomConstraint, widthConstraint])
VFL is also a better and clean approach. It actually gives a visualization of how constraint are setup.

UIScrollView with dynamically created UIButtons not Scrolling

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))

Swift error on Constraints

I'm trying to create some Constraints for a button that is moved with the UIPanGestureRecognizer
button.setTranslatesAutoresizingMaskIntoConstraints(false)
let line = ("\(p.x % snapX)")
let column = ("\(p.x % snapY)")
let constraint2 = NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(line))
let constraint3 = NSLayoutConstraint(item: button, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(column))
view.addConstraints([constraint2,constraint3])
but i have a "could not find member 'CenterX' error
P.s. line and column may take for example the value 27.6666564941406 and 0.666656494140625
Looks like the compiler is trying to find CenterX on the wrong enum type. Try using the full enum definition:
NSLayoutAttribute.CenterX
and
NSLayoutAttribute.CenterY