Is autolayout buggy? - swift

I have some problems with autolayout, and I am beginning to wonder if there are bugs in there. I have more issues, but this one seems very clear to me. Constraints are built by code, so I can show only screeshots from View hierarchy debugger.
Setup is easy - KeyboardView as parent, and inside four UILayoutGuides making margins at borders. There is of course more of it, but this should be enough for the issue. When app starts, everything is ok. But after some activating and deactivating groups of constraints by code, I end with this (no error in constraints is reported, layout just breaks silently)
Here is view debugger focused on the KeyboardView (it is the green one). It has a width of 414, which is correct, and is a result of autolayout constraints pinning its sides to superview.
But when I highlight one of LayoutGuides, I see this:
Layout guide has active constraint pinning its trailing edge to the trailing edge of superview (which is the KeyboardView). So it should be inside the green area, at the right edge. But it is totally out! Even if you look at frame, X is at 432.67, which is clearly outside its 414 parent. So the resulting frame constradicts the constraints, but system does not report any problem. I get NOTHING about contradicting constraints and need to break them. Even breakpoint at UIViewAlertForUnsatisfiableConstraints symbol does not fire. Layout just silently breaks without any reason.
Has anyone ever encountered such problems?

Well, I seem to find the problem, and it seems like a bug in autolayout to me. Problem was the grid of spacers (UILayoutGuides) between buttons in the keyboard. Their X and Y centers were positioned to parent's trailing and bottom edges with multiplier - in order to put them at the exact percentage of parent's width or height. Such constraint can't be done with anchors api (cant' use centerXAnchor with multiplier), but is perfectly valid constraint and can be made directly with NSLayoutConstraint() constructor.
These constraints usually work as they are supposed to, but under sume circumstances, after multiple activating and deactivating groups of constraints, they can break autolayout in a very weird way. Like the one that I asked about.
I resolved the problem by using helper UILayoutGuides (yes, even more of them :-/ ) that match its parent's width or height with multiplier. Which is OK; while position with multiplier makes problems, size with multiplier is OK. Then I used trailing and top edges of these helper to pin centers of my spacers to. Such construction now does work perfectly.

Related

Xcode 12: TableView Cell image too big and covering text

I made some custom tableview cells and while everything else with them works, the images are really big and I cant get them any smaller.
I did this and its still flooding: I added height and width constraints and a 10 constraint to the left of the ImageView, and selected these settings
I can suggest a few things you can try to achieve it. I have illustrated 1 & 2 on the attached image:
Suggestion 1 is to make sure there is no ambiguity or constraint collision. It seems you have set two constraints for the width of your image. You might be setting it to be 'greater than' the width you want it to be.
Suggestion 2 is to also provide a constraint between the image view and your label view for the heading in order to prevent an overlap.
Suggestion 3 is to make sure that your imageView has a setting of "Clips to bounds' checked on the inspector.
Suggestion 4 Change your content mode to Aspect Fill instead of Aspect Fit
Suggestion 5 Complete your constraints, make sure everything is blue. I don't see top and leading constraint. This will help remove any ambiguity.
Suggestion 6 Use the view debugger, see what constraint values are being used, and the debugger will also show you hierarchies and view layers, which will give you more idea of what is going on.
Your imageView seems to have no x and y constraints. I suggest you to give top and leading constraints for the beggining. You should never see red lines to have stable layouts.

My custom cell will not budge, everything I add gets stuck to the left wall

I am working with xcode and I can't seem to get my custom cell to budge. I have the constraints set up and even reset them a couple of times but they continue to look a lot different when I run my simulator.
Here is a screenshot of my constraints:
Here is an screen shot of my simulator:
I have tried deleting the labels and imageView and then adding it again and reset the constraints a few times. Anyone else getting these problems?
You are defining too many constraints. It is key for you to always use THE LEAST number of constraints as possible.
From what I can see you are giving the labels '5' and 'Orders need to be viewed' constraints to the leading edge of the cell. If you are also setting a second leading constraint to the image (hard to tell from the image, code would be easier to debug) this contradiction would break your constraints.
What you want is to have the image leading edge to the cell and give it a height and width and a top constraint only.
Give the '5' label 'horizontal spacing' ( ctrl drag ) to both the image and the second label.
Provide a height and width for it and a top constraint.
IMPORTANT
since you have defined a horizontal spacing from the '5' to the other label, you do not need to provide another leading constraint to the last label.
simply give it a height, width, top constraint and trailing edge to cell
That should be all you need !
If this is too confusing let me know and I can share some snippets for more visualization

Width limitations with constraints when window resized

I am trying to add a custom view in an nswindow in my osx app.
I need to give a minimum and maximum width values for the custom view which is located in the centre. The view's width should expand until a certain point (maximum width value) but should stop expanding if user continues to expand the window.
Thanks in advance.
You can do all of this with layout constraints.
First, we need to specify where the view should be relative to the window. For the sake of this tutorial, I'm going to assume you want it centered:
Next, we add our constraint for the minimum width:
To make this a minimum instead of an absolute width, click on the constraint and change it to "Greater Than or Equal" in the Attributes Inspector:
Now do the same thing, making another width constraint for the maximum. This time, set it to "Less Than or Equal":
Now the width constraints are set up. But we're not done. We've now set a minimum and a maximum, but the width is still ambiguous—there is no way for the layout constraint system to decide what exact width between 300 and 700 that it should actually be using at any given point. There are two steps to fix this. First, we need to make sure that the view will be entirely within the window and not run off the edges, so create some Greater Than or Equal constraints making sure it stays within its bounds:
(Also, make a trailing constraint which is set up identically).
Finally, we need one last set of constraints; we want some leading and trailing constraints, marked Equal, but with a lower priority:
(Also add a trailing constraint, identically configured)
What does this one do? Well, it tells us that, unless our other constraints (specifically the maximum width, in our case) make it impossible, we'd like the edges of the view to be the standard distance from the window edge. The reason we use 499 as the priority is because that the value of NSLayoutConstraint.Priority.windowSizeStayPut is 500. The documentation has this to say about .windowSizeStayPut:
It's generally not appropriate to make a constraint at exactly this priority. You want to be higher or lower. Constraints with higher priorities can adjust the window’s size. Constraints with lower priorities must be fulfilled using the current window size.
If we set our constraint to higher than 500, the system would restrict us from making the window too wide for these constraints to be valid. That's not what we want, since we want the edge spacing to expand in this case. So since we want to be able to break this constraint by resizing the window, we set it to slightly less than 500—so, 499. This means that the constraint system will try to put the view here, but if it can't do it because we made the window too wide, it will allow this constraint to break, although it'll still try to get as close as it can without breaking the other constraints. So your view will be at its maximum width, and centered in the window.
Voilà!

Container view getting truncated despite constraints in place

The scene has a container view inside of a superview, and I've constrained it with respect to the boundaries and 2 text boxes. Instead of "Numeric Value Please", I only see Nu... appearing on there. The console does not give me any constraint related warnings, and I don't understand why the blue view is able to fit in, but the controller is not.
Here are Alert Controller's constraints: http://i.stack.imgur.com/2xhZh.png. It's just constrained to the center.
Another picture of main view's constraints: http://i.stack.imgur.com/2qARq.png
The constraint to the right is too large (125), pushing the right edge of the container to the left.
You should just have: constraint from top (superview), constraint to left (the text field), height (optional), and slightly higher compression resistance. To prevent the text from going off to the right you can also have a >= constraint to the right (superview).
To break the text into two lines, set number of lines to 2 and choose "Word Wrap" + make sure you have a right side constraint and you are not constraining the height (too much).
Another remark: do you really need a "container" view? Why not just a plain UIView? Or does the label have its own controller? That seems like a somewhat convoluted design I think.

UILabel Text Not Wrapping

I am working on a Swift project with Storyboards where I want text to wrap in a label. In the old Objective-C version where I did not use a Storyboard I used the following settings and things worked perfectly.
Here are the settings for Swift
I have been reading about the potential auto layout issues with preferred width settings. I currently have them set to auto layout and the label itself is set to a width of 560. I've added a constraint to keep the label 20 pixels from the trailing superview and while I thought this would work I still cannot get the text to wrap. The dimension settings are below.
Can someone explain how to get the text to wrap?
First, the good news: You have set the label to 2 lines and Word Wrap. So it can wrap. Excellent.
Now you must make sure the label is tall enough. Either give it no height constraint, or give it a big enough height constraint that it can accommodate two lines.
Finally, you must limit its width. This is what causes the text to wrap. If you don't limit the label's width, it will just keep growing rightward, potentially continuing off the screen. The limit on the label's width stops this rightward growth and causes the text to wrap (and the label to grow downward instead).
You can limit width in several ways. You can have an actual width constraints. Or you can have a leading constraint and a trailing constraint, to something relatively immovable, such as the superview. And there is a third way: on the Size inspector (which you do also show, at the bottom right of your question), set the Preferred Width (it is shown at the top of the Size inspector): this is the width at which, all other things being equal, the label will stop growing to the right and wrap and grow down instead.
Declare your UILabel programmatically and give
yourUILabel.contentMode = .scaleToFill
yourUILabel.numberOfLines = 0
yourUILabel.leadingMargin(pixel: 10)
yourUILabel.trailingMargin(pixel: 10)
This worked for me.
Your text will wrap if you have provided lines number more than 1. However you may not be able to see it wrap if the label height is not enough to show the content. I suggest you to remove the height constraint or increase its value.
In case this helps anybody: I had followed the advice given here to fix my label not wrapping to two lines but nothing worked. What worked for me was I first deleted some of the relevant constraints in storyboard (I'm using auto layout) and saw that the label wrapped properly. I slowly added back the constraints I needed and everything still seems to work fine. So deleting and remaking your constraints may help.
What fixed this problem was changing the label type to "Placeholder" under Intrinsic Size in IB. When I changed this the text wrapped and the warnings went away.
As I see you interface builder. There are two problems. First one is with your constraints, and another one is with the property.
You gave it a fixed height which is wrong while line wrap. You need to make the auto-resizing label, i.e. remove height and add the bottom constraint or simple remove height depend on your situation. Your text is moving to the next line, but due to fixed constraint, you can't see it.
You enable the option to clip subviews which is wrong as it cuts your view and you are unable to view wrap word.
Add a new case:
DO NOT add constraints to your label with a TEXTVIEW, or the label will expand to right without limitation.
In my case i set my parent stackview alignment from center to fill and set UILabel to
label.textAlignment = NSTextAlignment.right