I have a view controller consisting mainly of 2 views.
One that has leading, trailing and bottom anchor aligned with superview and proportional height to superview(0.25), and a scroll view that aligns leading top and trailing to superview/safe area and bottom the other view.
I have a view defined in a xib-file which I create multiple times using Bundle.main.loadNibNamed("VariantResultSlide", owner: self, options: nil)?.first and add them to an array slides. I want to add them to my ScrollView:
for i in 0 ..< slides.count {
scrollView.addSubview(slides[i])
NSLayoutConstraint.activate([
slides[i].leadingAnchor.constraint(equalTo: (i==0) ? scrollView.leadingAnchor : slides[i-1].trailingAnchor),
slides[i].topAnchor.constraint(equalTo: scrollView.topAnchor),
slides[i].bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
slides[i].widthAnchor.constraint(equalTo: scrollView.widthAnchor),
slides[i].heightAnchor.constraint(equalTo: scrollView.heightAnchor)
])
if(i==slides.count-1) {
NSLayoutConstraint.activate([slides[i].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)])
}
self.updateResultSlides(index: i, vehicle: orderedVehiclesList[i])
}
But then Xcode gives me errors like:
2019-04-11 13:57:07.219263+0200 FleetView[545:190663] [LayoutConstraints] 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)
(
"<NSAutoresizingMaskLayoutConstraint:0x282cecbe0 h=-&- v=-&- FleetView.VariantResultSlide:0x107f214a0.height == UIScrollView:0x102919200.height + 99 (active)>",
"<NSLayoutConstraint:0x282c92300 FleetView.VariantResultSlide:0x107f214a0.height == UIScrollView:0x102919200.height (active)>"
)
and the slides are way too big.
But I can't find any place where I set another constraint for them. Why is this happening?
Your view implements top, bottom and height constraints so obviously its superview will need to resize - but it can't due to constraints created automatically from autoresizing mask. Disable it in you superview with
yourViewsSuperview.translatesAutoresizingMaskIntoConstraints = false
Related
What I want to achieve in AppKit (not in SwiftUI): [GIF] (example in SwiftUI)
The NSWindow max width should not be limited to the NSTextField max width.
The NSWindow min width should be limited to the NSTextField min width.
NSTextField need to have these parameters: [min width: 200, max width: 400]
I had several attempts to implement this behavior in AppKit. I've been trying to do this for a few days now, but it doesn't work. [PIC]
[GIF]
I tried to set the low priority on Leading / Trailing constraint.
This partially fixed the situation. I was able to change the size of the window normally, but the window size was not limited to the minimum size of NSTextField.
[GIF]
The important thing to notice here is that you only want the low priority constraints to be one way. That is, you don't want something like this:
// throughout the answer, I use "tf" for the text field, and "view" for its superview
let weakLeadingConstraint = tf.leadingAnchor.constraint(equalTo: view.leadingAnchor)
let weakTrailingConstraint = tf.trailingAnchor.constraint(equalTo: view.trailingAnchor)
weakLeadingConstraint.priority = .dragThatCannotResizeWindow
weakTrailingConstraint.priority = .dragThatCannotResizeWindow
Because these constraints would break when the window is resized, allowing the window to be resizable to any width where the leading and trailing anchors are "not equal" to those of the text field.
Instead, the low priority constraints should be >= or <= constraints. Think of the 2 equality constraints as the following 4 inequality constraints:
tf.leading <= view.leading
tf.trailing >= view.trailing
tf.leading >= view.leading
tf.trailing <= view.trailing
It is the first 2 that you want to break, leaving the last 2 (which says that the text field should always be within the window) in tact, when you resize the window.
The other constraints are quite straightforward, so I'll just present the whole code here:
tf.translatesAutoresizingMaskIntoConstraints = false
let weakLeadingConstraint = tf.leadingAnchor.constraint(lessThanOrEqualTo: view.leadingAnchor)
let weakTrailingConstraint = tf.trailingAnchor.constraint(greaterThanOrEqualTo: view.trailingAnchor)
weakLeadingConstraint.priority = .dragThatCannotResizeWindow
weakTrailingConstraint.priority = .dragThatCannotResizeWindow
NSLayoutConstraint.activate([
tf.centerXAnchor.constraint(equalTo: view.centerXAnchor),
tf.centerYAnchor.constraint(equalTo: view.centerYAnchor),
tf.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor),
tf.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor),
weakLeadingConstraint,
weakTrailingConstraint,
tf.widthAnchor.constraint(greaterThanOrEqualToConstant: 200),
tf.widthAnchor.constraint(lessThanOrEqualToConstant: 400),
])
I have a UIView containing:
UIButton: (contentMode = Aspect Fit)
UILabel:(numberOfLines = 0, lineBreakMode = byWordWrapping, contentMode = Aspect Fill)
UISwitch: ()
I would like the width and number of lines of the UILabel to adapt to the content of the localized text of UIButton and UILabel.
How should I proceed ?
Behavior expected:
____________________________________________________________________
| | | |
| UIButton | UILabel | UISwitch |
| | | | |
_________________________________v__________________________________
Fred
You will have to give it the required constraints in order to make it fit as you like. You need to provide more details, in order for me to tell you about the constraints you would want. With current information assuming that your button and switch have fixed widths, and are pinned at leading and trailing of superview end respectively. then go through a check of following constraints
(1) give leading constraint of your label equal to trailing constraint of button
(2) give trailing constraint of your label equal to leading constraint of switch
(3) give top and bottom constraint of your button equal to top and bottom constraint of label
(4) give top and bottom constraint of your switch equal to top and bottom constraint of label
Finally, provide a constraint for the y position of your label, and you are good to go.
Another potential solution is using a horizontal stack view, which will save a lot of these constraints.
Here is what I tried... but the size of my button is not as small as possible (I expext it to fit the text)
So, I have added these constraints
NSLayoutConstraint.activate([
resetButton.leadingAnchor.constraint(equalTo: bottomView.leadingAnchor),
resetButton.trailingAnchor.constraint(equalTo: rawLabel.leadingAnchor),
rawLabel.trailingAnchor.constraint(equalTo: directSwitch.leadingAnchor),
directSwitch.trailingAnchor.constraint(equalTo: bottomView.trailingAnchor),
resetButton.topAnchor.constraint(greaterThanOrEqualTo: bottomView.topAnchor),
rawLabel.topAnchor.constraint(equalTo: bottomView.topAnchor),
directSwitch.topAnchor.constraint(greaterThanOrEqualTo: bottomView.topAnchor),
resetButton.bottomAnchor.constraint(lessThanOrEqualTo: bottomView.bottomAnchor),
rawLabel.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor),
directSwitch.bottomAnchor.constraint(lessThanOrEqualTo: bottomView.bottomAnchor),
resetButton.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor),
rawLabel.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor),
directSwitch.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor)
])
and this viewWillAppear func
override func viewWillAppear(_ animated: Bool) {
resetButton.sizeToFit()
rawLabel.numberOfLines = 0
rawLabel.lineBreakMode = .byWordWrapping
rawLabel.preferredMaxLayoutWidth = bottomView.frame.width - resetButton.frame.width - directSwitch.frame.width
}
i have a tableviewCell containing 2 labels.
The right one has a fixed width and fixed trailing space to superview and the left one a fixed leading space to superview and trailing to right label.
Sometimes i only need the the left label and in this case i want the left one to have a fixed trailing space to superview instead. So, i created a second inactive constraint and do this in my code:
if(entry.right.isEmpty) {
tableCell?.longConstraint.isActive = true
tableCell?.shortConstraint.isActive = false
tableCell?.rightLabel.isHidden = true
} else {
tableCell?.longConstraint.isActive = false
tableCell?.shortConstraint.isActive = true
tableCell?.rightLabel.isHidden = false
}
but when i load the table all displayed cells have the default constraint active and only after scolling out of view and in again, they are displayed correctly.
For an easy way you can embed them inside a horizontal UIStackview and set
self.rightlb.isHidden = true
and it will disappear with no width automatically , also in your current code make sure
tableCell?.layoutIfNeeded()
after you change the constraints
Try adding this code after adjusting constraints programmatically
tableCell?.setNeedsLayout()
tableCell?.layoutIfNeeded()
Hope this works
I am struggling with adding one button from code to the right corner of the view.
Could someone explain me how can i do this without setting the left constraint ? This would be the left upper V:|-10-[v0], H:|-10-[v0] what would be inversion of it ? I was trying with this : V:[v0]-10-|, H:[v0]-0-| but it does not work like i thought
Thanks in advance!
Based on the comments, I'd like to provide two answers on how to place a UIButton on the top right.
VFL:
Your vertical pin is for the bottom right, not the top. Instead of V:[v0]-10-|, where the "pipe" character (that designates the bounds of the screen) is at the end, place it at the beginning - |-10-[v0].
Provided you've given the button some sort of height/width - which I think you have as the code for "top left" works - this should fix things.
Anchors
Introduced in iOS9, layout anchors (along with layout guides) are a third way to code auto layout. Like NSLayoutConstraints, this is less "visual" than VFL. But unlike NSLayoutConstraints it's less verbose - thus more "Swiftier" IMHO.
To pin a UIButton to the top left, you still need to give auto layout four things - height, width, and X/Y positions. In the following I'm assuming the superview of v0 is called view, like the root view of a UIViewController.
// declare your button
let v0 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
// remember, you ALWAYS need to turn of the auto resize mask!
v0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v0)
// create a square button
v0.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
v0.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
// pin the button 10 points from the left side of the view
v0.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
// here's how you would pin the button 10 points from the right side of the view
// note the use of a negative here!
// v0.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
// pin the button 10 points from the top of the view
v0.topAnchor.constraint(equalTo: view.topAnchor, constant: 10).isActive = true
}
Like NSLayoutConstraints, layout anchors have constants and multipliers, which you may change if you declare a name for the constraint.
You may combine NSLayoutConstraints with NSLayoutGuides for some nice "adaptive layouts". These guides act like "spacer/invisible" UIViews except for the overhead - they aren't views. You can get a set of Apple "standard" margins (UIView.layoutMarginsGuide), or you can create a set of equally size dynamic guides to space things out equally.
Here's two blogs about layout anchors and layout guides. The examples are written in Swift 2 but there's no syntax changes for Swift 3.
Greeting:
I'm trying to center a UILabel '1' inside a green button.
Here's my code:
let dayFrame = CGRectMake(1, 1, 16, 16)
let myLabel1 = UILabel(frame:dayFrame)
myLabel1.font = calFont
myLabel1.tag = 100
dayButton1.addSubview(myLabel1)
var viewDictionary:Dictionary = ["myLabel": myLabel1]
dayButton1.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[myLabel]|",
options:nil, metrics:nil,
views:viewDictionary))
dayButton1.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[myLabel]|",
options:nil, metrics:nil,
views:viewDictionary))
However I got the following runtime error:
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)
(
"<NSIBPrototypingLayoutConstraint:0x7fbebae37010 'IB auto generated at build time for view with fixed frame' H:[UIButton:0x7fbebae47ac0(28)]>",
"<NSLayoutConstraint:0x7fbebacb5fc0 H:|-(0)-[UILabel:0x7fbebae9aa00'1'] (Names: '|':UIButton:0x7fbebae47ac0 )>",
"<NSLayoutConstraint:0x7fbebacd68a0 H:[UILabel:0x7fbebae9aa00'1']-(0)-| (Names: '|':UIButton:0x7fbebae47ac0 )>",
"<NSAutoresizingMaskLayoutConstraint:0x7fbebc421b70 h=--& v=--& UILabel:0x7fbebae9aa00'1'.midX == + 9>"
)
I'm not sure what I'm doing wrong. I merely added a Vertical & Horizontal constraint to UIButton's subview, 'UILabel' of a certain dimension.
Try adding
label.translatesAutoresizingMaskIntoConstraints = NO
to the top of your code
Based on the feedback...
I got the correct solution:
myLabel1.setTranslatesAutoresizingMaskIntoConstraints(false)