Which view to expand when adding constraint between two views - swift

I'm taking the cs193p online course to learn ios development. Yet I'm confronted with a problem when I tried to add spacing constraint between two stack views. (The one with blue buttons(view1) and the one with labels(view2) )
I want the view1 to expand while keeping view2 unmodified. But it turned out that view2 always expand, even if I set the content hugging priority of view 2 higher than that of view1. How could I solve this problem?

Unless you've given your labels an explicit width, their width will be set by their intrinsic content size. The hugging priority for the labels is low, so the labels are free to grow to fill their container. So, the containing stack view will always be hugging its content since the labels can grow. You need to restrict the growth of the labels' widths in order for the hugging priority of the stack view to have any effect.
The solution is to either give your labels an explicit width constraint, or even easier to set their hugging priorities to be high as well. This will keep the labels from growing and will allow the stack view to hug the label's minimum size. Finally, Auto Layout will choose to expand view1 instead.

Related

Changing Stack View dimensions to be a ratio

I am wondering how I can change the dimensions of a stack view to be a ratio, specifically 7:6. So far, I have constrained the Stack View with "Align Center X to: Superview" and "Height Equals: 400" and "Align Top to: Safe Area Equals: 100." How can I maintain a constant ratio between the width and the height across all devices? Thanks!
For User Interface, I am using Storyboard, not SwiftUI.
What I have right Now
I am not exactly sure why this doesn't work, but it is probably my understanding of aspect ratio. My main issue is how to use the (phone width - 20 points) to determine the height so that it is a ratio.
Expected result, but I don't want to manually set the height and width, rather a ratio
I don't want to manually set the height and width
Then you should remove the "Height Equals: 400" constraint that you currently have! After that the layout should be fixed. It should look like:
Just for completeness' sake, all the stack views should have distribution=fill equally, and alignment=fill.
The height=400 constraint is causing the constraints to conflict. If height = 400, then width would be about 467 to get an aspect ratio of 7:6, but the width of the super view isn't enough for that. But you also require the leading and trailing of the stack view to be pinned on the leading and trailing of its super view! These constraints can't be simultaneously satisfied.
Note that this layout doesn't look quite nice when in landscape, since the width would be very large and the available height is small. You might want to add variations to install/uninstall constraints based on size classes. In landscape mode, you could pin top and bottom rather than leading and trailing, for example.

How to add subviews in stackview top to bottom?

I'm adding labels to a stackview and I'm having trouble getting them to add to the top of the stackview rather than the middle.
I'm trying to accomplish this with the following code:
let textLabel = UILabel()
textLabel.textColor = .white
textLabel.widthAnchor.constraint(equalToConstant: self.stkCombatStackView.frame.width).isActive = true
textLabel.text = "This is a test"
textLabel.textAlignment = .left
stackview.addArrangedSubview(textLabel)
I want the labels to be added from top to bottom, how can I do this? without the weird spacing?
I have the spacing in the inspector set to 1
(I also have the stackview nested in a scrollview in the storyboard but i can't seem to scroll the stackview at all)
I'm adding labels to a stackview and I'm having trouble getting them to add to the top of the stackview rather than the middle.
You should probably call insertArrangedSubview(_: at:) instead of addArrangedSubview(). The insert... method lets you specify the index at which to insert the new view.
I want the labels to be added from top to bottom, how can I do this? without the weird spacing?
Are you sure you're using the right tool for the job? A stack view is good for containing a heterogeneous list of views in a fixed space, and it moves and/or resizes the views in the list to fill the view evenly. Take a look at the Distribution values: you can either fill up the stack view by resizing the contents in a couple different ways, or you can spread the contents evenly across the height (or width) of the stack view. There's no option for just listing the contained views and leaving extra space at the bottom, which seems to be what you want.
Some options you could consider:
use a UICollectionView: Collection views are incredibly flexible, letting you lay out a list of items in any conceivable geometry; the provided layout manager will surely work for your needs, but if you don't like it you can write a layout manager of your own or use someone else's. UICollectionView is a subclass of UIScrollView, so scrolling is easy.
use a UITableView: A table view gives you a vertical list of (usually, but not necessarily, similar) cells that can contain anything you want, and that top to bottom behavior that you're looking for is inherent in the way a table works. UITableView is also a UIScrollView subclass.
roll your own: It's not that hard to create a view that simply contains a list of other views and lays them out according to any algorithm you like; if a table or collection won't work for your needs (which seems unlikely), writing your own container will work better than trying to force UIStackView into submission.

Make intrinsicContentSize adapt to external constraints

The Context
I often have situations where I want multiple NSTextViews in a single NSStackView. Naturally, Auto Layout is not pleased with this since this makes height ambiguous (assuming the stack view is not set to fill equally). Even after adding constraints to resolve these issues, macOS Interface Builder appears to have a bug where it refuses to actually update frames when asked.
For this reason and others, I'm attempting to create a TextBox class (subclassing NSView) to encapsulate an NSTextView (and associated scroll view) and include an intrinsic content size to avoid layout issues. The intrinsic content size would be calculated based on a user-specified min and max number of lines (to display without requiring scroll). In other words, up to a certain max number of lines, TextBox will resize itself so that scrolling is unnecessary.
The Problem
This would seem to require an intrinsicContentSize that is dependant on frame width.
But, intrinsicContentSize documentation states:
The intrinsic size you supply must be independent of the content frame, because there’s no way to dynamically communicate a changed width to the layout system based on a changed height.
However, Auto Layout Guide states:
A text view’s intrinsic content size varies depending on the content, on whether or not it has scrolling enabled, and on the other constraints applied to the view. For example, with scrolling enabled, the view does not have an intrinsic content size. With scrolling disabled, by default the view’s intrinsic content size is calculated based on the size of the text without any line wrapping. For example, if there are no returns in the text, it calculates the height and width needed to layout the content as a single line of text. If you add constraints to specify the view’s width, the intrinsic content size defines the height required to display the text given its width.
Given that when scrolling is disabled in a text view:
If you add constraints to specify the view’s width, the intrinsic content size defines the height required to display the text given its width.
Then it seems there is a way to do what I want by perhaps looking at existing constraints.
The Question
How can I define an intrinsic content size that calculates height based on otherwise specified width, as described in the last quoted sentence above?
The solution should produce the effect described in "The Context" and not produce errors or warnings when used inside a Stack View.

Auto Layout issues

I am trying to get a layout working where I have 9 squares set 3 x 3 and on all device sizes, they are square.
I have tried endless ideas to make it work but can't seem to get it to stay squares on all devices.
I attached below, a picture showing the results and current constraints on the top left corner square.
Any help would be awesome!
The best approach would be use the stackView. The advantage will be you do not have to deal with the much constraints. So select the first rows three view horizontally then click on the Embed in Stack button whose axis should be horizontal inside your storyboard. Follow the same for second and third rows. Also inside stackview you can mention the spacing you want.
So now you have three stackView for all the three rows. After that select all three stackView then click on the Embed in Stack button and whose axis should be vertical and you can mention the spacing you want.
So advantage of doing that is you do not have to worry about the constraints. Finally you only have to apply the constraint on your main stackView which hold all your child stackView
While I totally agree that UIStackView is a great option, you can also add Aspect Ratio constraints (with a Multiplier of 1) to your squares and ensure that they remain squared (as nothing about your current layout demands that your views should be squares).
If you want your 9 squares to remain in the center of the superview, I recommend adding them to an invisible intermediate view and center that within the superview.

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.