I am trying to add constraint for right attribute to a label and a button programmatically but it doesn't work for right side constraint.
Button and label are on both the same UITableView and same cell. They both have simple width, height, x and y position constraints set in storyboard. I need to change the x position in code.
Following left constraint is working OK, I changed the value and it's reflected in simulator.
dateLabelLeft = NSLayoutConstraint(item: dateLabel,
attribute: .Left,
relatedBy: .Equal,
toItem: self.view,
attribute: .Left,
multiplier: 1,
constant: 50
I just changed the .Left with .Right and even tried .Trailing but it doesn't work. I have double checked the storyboard and there is no red line for the Button.
buyButtonRight = NSLayoutConstraint(item: dateLabel,
attribute: .Right,
relatedBy: .Equal,
toItem: self.view,
attribute: .Right,
multiplier: 1,
constant: 50
edit :
constraints are added using view.addConstraint
I think you dont need to add constraints programmatically if you have added from storyboard....alternatively you can create the IBOutlet of specific constraints and can change the constant value of constraint you mapped programmatically.
You realize that creating an NSLayoutConstraint does nothing? You have to add it to a view as well.
Related
I'm creating a custom keyboard in Xcode with swift. Everything runs great but I am running into a problem with constraints. Ill explain what I've done and what I am looking to do.
what I have done:1)I have created a 'world' button that will switch between the iOS default keyboard and the custom keyboard. It is constrained to the bottom left of the view, no matter what device it is loaded onto (iPhone 5,6,7 iPad etc). 2)I have then created a collection view that is constrained to start at the edge of the world button no matter the device. 3)I have created a delete button that is constrained to the bottom right of the view, no matter the device.
what I want to do: 1)I want the collection view to start at the world button and end at the delete button, no matter the device.
The trouble I am having is that the delete button overlaps the collection view on smaller devices. I want the collection view to stop at the delete button but cannot figure out why my constraints are not working.
These are the relevant constraints for the collection view.
// create the constraints
// leading constraint
let categoriesCollectionViewLeadingConstraint = NSLayoutConstraint(item: categoriesCollectionView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: backButton, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
// add the leading constraint
view.addConstraint(categoriesCollectionViewLeadingConstraint)
// bottom constraint
let categoriesCollectionViewBottomConstraint = NSLayoutConstraint(item: categoriesCollectionView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
// add the bottom constraint
view.addConstraint(categoriesCollectionViewBottomConstraint)
// trailing constraint
let categoriesCollectionViewTrailingConstraint = NSLayoutConstraint(item: categoriesCollectionView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0)
// set the priority to less than 1000 so it works correctly
categoriesCollectionViewTrailingConstraint.priority = 999
// add the trailing constraint
view.addConstraint(categoriesCollectionViewTrailingConstraint)
I think you should constraint your collection view like this:
// trailing constraint
let categoriesCollectionViewTrailingConstraint = NSLayoutConstraint(item: categoriesCollectionView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: - deleteButtonWidth)
I have set the following constraint programmatically on a UISwitch that was set as an IBOutlet:
func setConstraints {
let leadingConstraintTimeSwitch1 = NSLayoutConstraint(item: timeSwitch, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: timeLabel, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 10)
view.addConstraint(leadingConstraintTimeSwitch1)
Whenever I change the constant of this constraint, the X position of the switch remains the same. However, when I go to the Size Inspector of the switch and change its X value, the switch's position does update correctly, however I do not want to use the Size Inspector. How can I get the constraint set programmatically to override the X value in the Size Inspector? I have also added a constraint specifying the Y position of the switch (a bottom constraint), and this one does work. Thanks!
There is not alot of information to go from in your description..
I normally add my constraints like so:
NSLayoutConstraint(item: timeSwitch, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: timeLabel, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 10).active = true
are timeSwitch and timeLabel part of the view hierarchy?
have you set translatesAutoresizingMaskIntoConstraints to false?
Are there any other constraints at play that could be affecting it?
I have a controller where I add a subview programmatically. With the configuration of the subview I add autolayout constraints programmatically. Everthing is working except that the view doesn't react on touches if I add the constraints and even the set backgroundcolor is not displayed.
The buttonView should be displayed in the lower right corner of my parent view.
Any ideas what could be wrong?
Here is how I add my constraints:
private func configureAutolayoutConstraints(buttonView: UIView, parentView: UIView){
buttonView.translatesAutoresizingMaskIntoConstraints = false
let bottomConstraint = NSLayoutConstraint(item: buttonView, attribute:
.Bottom, relatedBy: .Equal, toItem: parentView, attribute: .Bottom, multiplier: 1.0, constant: -130)
parentView.addConstraint(bottomConstraint)
let trailingConstraint = NSLayoutConstraint(item: buttonView, attribute:
.Trailing, relatedBy: .Equal, toItem: parentView, attribute: .Trailing, multiplier: 1.0, constant: -90)
parentView.addConstraint(trailingConstraint)
}
Autolayout engine needs at least 4 constraints to determine the frame of view. You have applied bottom and trailing constraints only. You need either width+height OR leading+top constraint to make it work.
I have constraint code that lays out a number of UILabels (4+) vertically from top to bottom inside a container view (a regular UIView). I now want my container view to be sized so that its height matches the bottom of that last label that I've added.
I have tried this:
let constraintPanelHeight = NSLayoutConstraint(item: cell.panelOptions,
attribute: .Height, relatedBy: .Equal, toItem: priorLabel!,
attribute: .Bottom, multiplier: 1, constant: 0)
cell.contentView.addConstraint(constraintPanelHeight)
but this generates an Invalid pairing of layout attributes error since I'm matching .Height of one view with .Bottom of a subview (I'm guess that's why).
How can I auto-size my containing view like this?
I don't know what your trying to achieve there exactly. If you want to pin the one cell to the bottom of the other, you'll have to use attribute .Top and another constraint for the height. For example: you have 10 labels in your view, then set your height to one tenth of the superview:
let heightConstraint = NSLayoutConstraint(item: cell.panelOptions, attribute: .Height, relatedBy: .Equal, toItem: superview, attribute: .Height, multiplier: 0.1, constant: 0)
But since iOS9 there's also the UIStackView which makes laying out subviews in a view (vertically or horizontally) very easy. Have a look at that if you want to spread your labels evenly in your superview.
If you are fixed number of views the easiest and most readable way is the use the visual layout format and constraints like this:
NSLayoutConstraint.constraints
WithVisualFormat("V:|[view1][view2][view3]|",
options: NSLayoutFormatOptions.AlignAllCenterX,
metrics: nil,
views: ["view1": view1, "view2": view2,"view3": view3])
If you want to add a variable number the principle is the same but achieved with a loop. You shouldn't set the height of anything. Let the intrinsicContentSize of each label size the container from the inside. You might need to set the priority of contentCompressionResistance of each label to 1000 just to be sure the labels don't get squashed. Keep in mind the you will need horizontal constraints as well but they should be simpler to work out.
And here's the version for a variable number of subviews:
var prevView : UIView?
for view in views{
container.addSubview(view)
//
// Add horizontal constraints for each view to fit the container
// exclude for simplicity
// Add vertical constraints
if prevView == nil{
container.addConstraint(NSLayoutConstraint(item: container,
attribute: .Top,
relatedBy: .Equal,
toItem: view,
attribute: .Top,
multiplier: 1, constant: 0)
)
} else if view == views.last!{
container.addConstraint(NSLayoutConstraint(item: container,
attribute: .Bottom,
relatedBy: .Equal,
toItem: view,
attribute: .Bottom,
multiplier: 1,
constant: 0))
} else if let prev = prevView {
container.addConstraint(NSLayoutConstraint(item: prev,
attribute: .Bottom,
relatedBy: .Equal,
toItem: view,
attribute: .Top,
multiplier: 1,
constant: 0))
}
prevView = view
}
I am trying to put an UIImageView on the upper center of screen horizontally which is coding in the viewDidLoad( ). And I have two pre-plans, which means I do not know the specify functions or APIs.
1). I want to set a variable which equal to the half of screen's width. And I know it gonna work with something about 'bounds' or 'frame'. Pathetically, I do not know those specify function or parameters.
2). In order to make sure the resolution, I want to figure out the currentDevice. After that, I can set UIImageView with CGRectMake((resolution.x)/2, y, length, width). Is there any function can confirm the currentDevice?
And I think the first one is more efficient than the second one.
A big appreciate for your help and guidance.
Ethan Joe
I would suggest to use autolayout:
var imageView = UIImageView()
imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(imageView)
// Create the constraints and add them to a Array
var constraints = [AnyObject]()
// This constraint centers the imageView Horizontally in the screen
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0))
// Now we need to put the imageView at the top margin of the view
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 0.0))
// You should also set some constraint about the height of the imageView
// or attach it to some item placed right under it in the view such as the
// BottomMargin of the parent view or another object's Top attribute.
// As example, I set the height to 500.
constraints.append(NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 500.0))
// The next line is to activate the constraints saved in the array
NSLayoutConstraint.activateConstraints(constraints)
This code horizontally centers the imageView in every device. I suggest you investigating AutoLayout, it's a nice feature.
Here's a nice link where you can start with it:
Learning to love Auto Layout... Programmatically
So, the best solution to this would be to utilize auto layout.
Say your UIImageVew is defined as var imageView = UIImageView!.
Then you would do the following.
var centerXConst = NSLayoutConstraint(item: imageView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 1)
var centerYConst = NSLayoutConstraint(item: imageView, attribute: .CenterY, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 1, constant: 1)
self.view.addLayoutConstraints([centerXConst, centerYConst])
What you are doing is setting the center of the imageView on the x and y axis respectively to the same as the center of the view on the x and y axis respectively.
To find the width of the view as you proposed in 1), do the following:
var screenWidth = self.view.bounds.width