ios correct way to use constraintLessThanOrEqualToSystemSpacingAfter for trailingAnchor - ios

I'd like to programmatically layout a UILabel that should fit the width of the screen, with the system spacing as left and right insets. Here's my code:
statusLabel.font = UIFont.systemFont(ofSize: UIFont.smallSystemFontSize)
statusLabel.numberOfLines = 0
statusLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(statusLabel)
statusLabel.topAnchor.constraint(equalTo: otherView.bottomAnchor, constant: 0),
statusLabel.leadingAnchor.constraintEqualToSystemSpacingAfter(view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1),
statusLabel.trailingAnchor.constraintLessThanOrEqualToSystemSpacingAfter(view.safeAreaLayoutGuide.trailingAnchor, multiplier: 1),
statusLabel.bottomAnchor.constraint(equalTo: someOtherView.topAnchor, constant: 0)
Here is the result:
the label is laid out using the system spacing as the left inset, as intended, but its trailingAnchor seems to be equal to the superview's trailingAnchor rather than adding a system spacing between the two.
I've tried using constraintEqualToSystemSpacingAfter and constraintGreaterThanOrEqualToSystemSpacingAfter but got the same results.
Any ideas on how to get the system spacing between the label and its superview's trailing anchors?

Reverse the order Like this
view.safeAreaLayoutGuide.trailingAnchor.constraintEqualToSystemSpacingAfter(statusLabel.trailingAnchor, multiplier: 1).isActive = true
view first & statusLabel next.

Related

Swift iOS Layout Constraint. Using Constant that is proportional to view height programatically

I am laying out a view programatically in Swift for iOS, but struggling to get my constraint quite how I want it. This is what I currently have:
NSLayoutConstraint.activate([
Logo.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30),
Logo.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -30),
Logo.heightAnchor.constraint(equalToConstant: 55),
Logo.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 150),
])
This is fine on large screens but as the screen gets smaller I want to close the space between the Logo and the label. Currently this is set to a fixed constant of 150. What I would like to do is use a multiplier here that is based on the view height (or something similar) but I can not figure that out. How should I define the constraint to do this? Thanks!
You can try
/* Play with percent as you need also you can check current
device type iphone/ipad and set it accordingly */
let height = UIScreen.main.bounds.height * 0.25
logo.topAnchor.constraint(equalTo: label.bottomAnchor, constant: height),

Swift trailing constraint spacing depending on width of superview multiplied with a value (programmatically)

Let's say I have a UITableViewCell.
In the contentView of the cell, I have a subView. The trailing of the subView to the contentView is depending on the width of the contentView, multiplied with a value.
What I'm trying to achieve is:
let trailingSpacing: CGFloat = contentView.frame.size.width * 0.2
subView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -trailingSpacing).isActive = true
The piece of code above is what I was trying to do in layoutSubviews() of the UITableViewCell. It's not working and besides that, it doesn't feel right. Is there a more clean way to do this? I don't think you can do this in 1 constraint, but maybe I'm wrong.
The constraints are alle done in code, there is no storyboard/xib/nib.
Thanks in advance!
I'm not sure whether you're able to solve it with a single constraint, but you can add a spacer view to solve this. Anchor the spacer view to the trailing of your container, and the trailing of your "target" view to the leading of the spacer. Then, give the spacer a width that's a multiple of the container's width:
let constraint = NSLayoutConstraint(
item: spacer,
attribute: .width,
relatedBy: .equal,
toItem: container,
attribute: .width,
multiplier: 0.2, // <-- tweak this
constant: 0
)
container.addConstraint(constraint)
(You may need to switch space and container in the constraint, I always forget which is the one the multiplier is applied to.)
You can even do this solution in Interface Builder.

Possible to have fine-grained horizontal Auto Layout control in vertical UIStackView?

I'm currently working with a vertical UIStackView in which each view has a UILabel to be displayed on the left and a UIButton to be displayed on the right. The leading constraint for the label should be different than the trailing constraint for the button and the entire view should take up the width of the screen. The alignment for the stackview is fill and the distribution is fillEqually.
The problem I'm running into is that Auto Layout doesn't seem to be respecting the trailing constraint that I'm trying to set for the button on fill alignment (or any other alignment, for that matter). No matter what I put for it, the system sets it to 20. I've tried center, leading, and trailing alignments but they don't work for what I'm trying to do. Is it possible to have the degree of horizontal layout control I'd like with a vertical stackview?
My constraints (radioButton trailing constraint constant is set to 0):
private func sharedInitialization() {
translatesAutoresizingMaskIntoConstraints = false
textLabel.translatesAutoresizingMaskIntoConstraints = false
radioButton.translatesAutoresizingMaskIntoConstraints = false
addSubview(textLabel)
addSubview(radioButton)
NSLayoutConstraint.activate([
radioButton.widthAnchor.constraint(equalToConstant: 30),
radioButton.heightAnchor.constraint(equalToConstant: 30),
radioButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
radioButton.centerYAnchor.constraint(equalTo: centerYAnchor),
textLabel.trailingAnchor.constraint(equalTo: radioButton.leadingAnchor, constant: -10),
textLabel.topAnchor.constraint(equalTo: topAnchor, constant: 22),
textLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
bottomAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 22)])
}
Visual debugger:
I've looked at Prevent vertical UIStackView from stretching a subview? but that doesn't seem quite applicable to my situation. Thanks in advance for any help!

setting textfield constraints to hold effective in screen sizes 4.5 in to 6.5 in

if I set fixed width it either appears too large for small screen (4.5 in) or too small for large screen (6.5 in)
and
is there any special way to ensure the constraints hold good in all
constraints
Like Jatin mentioned in the comments, you can use leading and trailing anchors relative to the view like this,
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
Or, you could set the width as a multiplier to the width of the view.
textField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.80).isActive = true
Note: Change the constant and multiplier values to suit your needs.

iOS constraints doesn't allow to use multiplier

I am trying to layout some custom views and when I try to activate the constraints, Xcode says that I can't use multiplier. Here is an example of the code:
class MenuView: UIView {
var addButton: AddButton!
var settingsButton: SettingsButton!
// ........
func setConstraints (withBarReference reference: NSLayoutYAxisAnchor) {
NSLayoutConstraints.activateConstraints([
// ........
addButton.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor, multiplier: 0.5),
// ........
settingsButton.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor, multiplier: 1.5)
])
}
}
The thing here is that Xcode gives a syntax error on the contraintEqualToAnchor: functions and says that I should replace "multiplier" to "constant".
Why can't I use the multiplier option with the X center anchors?
You can't set multiplier using helper functions, but you can set multiplier using NSLayoutConstraint initializer. Just got stuck by this myself, but found the answer.
Your code: addButton.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor, multiplier: 0.5)
Correct code: NSLayoutConstraint(item: addButton, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 0.5, constant: 0)
Also, don't forget to activate this constraint by typing isActive = true
Previous answers work very weird now.
You can simply create UILayoutGuide with multiplier width/height with view and set guide.trailing equal to the centerX of your subview.
For example, if you need to place the addButton in the first 1/3 of a view and settingsButton in 2/3 you can simply set two layout guides
let addButtonGuide = UILayoutGuide()
self.addLayoutGuide(addButtonGuide)
addButtonGuide.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/3).isActive = true
addButtonGuide.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
addButton.centerXAnchor.constraint(equalTo: addButtonGuide.trailingAnchor).isActive = true
// same for settingsButton but using 2/3 for the multiplier
But the really best way is to use UIStackView and set its distribution property to equalCentering.
Another option is to use uncommon Auto Layout API to create NSLayoutDimension between two centerXAnchors and make constraint to self.widthAnchor:
addButton.centerXAnchor.anchorWithOffset(to: self.centerXAnchor)
.constraint(equalTo: self.widthAnchor, multiplier: 0.25).isActive = true
self.centerXAnchor.anchorWithOffset(to: settingsButton.centerXAnchor)
.constraint(equalTo: self.widthAnchor, multiplier: 0.25).isActive = true
It seems that in IB you can use the multiplier option with Center X and obtain the effect you're looking for (set the center of button1 at 1/4 the width of the view it's in, and the center of button2 at 2/3 of the width of the view it's in):
.
I tried to use it both in code and in IB, and in code I got the same error as you.
Surprisingly, in IB it worked, no errors, no warnings. (I am using Xcode 7, will try it in Xcode 8 to see if it still works).
You can't use multipliers on NSLayoutXAxisAnchor anchors - multiplying by a position along a line doesn't make sense in a way that the constraints system can understand. You can only use multipliers with NSLayoutDimension anchors, which measure lengths, like the width.
The layout you are trying to make would be better achieved using a stack view.

Resources