Using Intrinsic Content Size + Compression/Hugging priorities in StackView - autolayout

I am trying to have a table view cell be laid out with automatic dimensions using estimatedRowHeight and automatic dimensions. The cell will hold a Stack View in its content view.
TheStack View is vertical axis and holds three arranged sub view. A label followed by a view, with three labels as subviews, following by a label. Its alignment is center. Its
My goal is for the intrinsic content size (height specifically) determine the height of the Stack View.
The ultimately goal is to have these three vertical arranged subviews determine the height of the Stack View, which determines the height of the content view and therefore the tableview cell which will dynamically receive this height.
The middle arranged subview is a "container" view that holds three labels. Each label has a constant height of 22. The reason I want this container layer in between the labels and the stack view is because it just simpler to do these specific constraints outside of the Stack View's control. However, I want this container view's intrinsic content size (something like 22 + 22 + 22 + spacing/margin) to factor into the Stack View's intrinsic content size.
Now I know UIView's by default don't have an intrinsic content size. Does that mean I have to give this container view a custom class and override intrinsicContentSize to inform the StackView of the three labels height inside of it?

Related

How to properly constrain Vertical StackView with multiple labels in Dynamically heighted TableView Cell

I have a tableview cell that contains a horizontal UIStackView. Inside it is an UIImageView (on the left, 100x100 dimensions) and a vertical UIStackView (on the right) that contains 4 labels. The vertical UIStackView is constrained to the UIImageView's top and bottom anchors. But the bottom constraint is "less than or equal to".
I am setting the text property on these labels but if the text is nil I hide that label. Stack View than sets the height of that label to 0 and it doesn't appear in the Stack View. Now the idea is if some labels are hidden, the combined intrinsic content size's of the remaining labels will define the height of the vertical UIStackView and it will decrease in height based on that "less than or equal to" bottom constraint.
This doesn't work though. Take the case where the 2nd and 4th labels have been hidden. The 1st label is normal height. But the 3rd label stretches all the way down to the bottom of the UIImageView. This is in contrast to my expectation that the intrinsic content sizes of the labels would be less and the label's UIStackView would shrink.
I'm guessing there is some priorities that might need to be tuned to get this working properly. This whole view hierarchy is contained in a UITableViewCell and that has dynamic height applied which I hope doesn't cause any problems.
So if the intended behavior is that when I hide labels the vertical UIStackView shrinks, what constraints must I add/delete or which priorities must be set?

iPhone Autolayout UIText suffocation

I know I can fix this programmatically and I know I could set the text to tighten / scale but I would like to know how to get this text to extend organically to a third line on small screens. How can I accomplish that?
There are a couple of things you need to take care of before your label grows:
Make sure the 'number of lines' field in the attributes inspector is set to zero. Setting it zero allows the label to grow depending upon the content it has.
If the label is in a container view, make sure you haven't specified the height constraint explicitly on the container view. Since the container view should generate its height from its subviews and the subviews will generate their height from the content they have. Its sort of a chain process that goes on if you have a deeper hierarchy.
Make sure there is no sibling view to the container view with an explicit height that might cause your container view to shrink while maintaining its own height. This point may also apply even if your label is not within some container view.
In the image below, the container view(gray one) is bound from three sides allowing it to grow from the bottom.
Below image shows the constraints applied to the content views of the container. The container is driving its height from its content views.
Below I have increased the text of the label from a single line to three lines. At this point the label tries to expand horizontally but since the container view is bind with the super view on both sides the label has only one direction left to increase itself. It increases downwards pushing the textfield and button down and since the button is tied with the bottom of the container view it pulls the container view increasing its height.

JavaFX alignment of Label in GridPane

I'm confused as to why setting the Label.setAlignment(Pos.CENTER_RIGHT) does not affect the alignment of a label that is then added into a GridPane? The only way to do it is seemingly through the grid (e.g. ColumnConstraints) or by e.g. adding the Label to a HBox that has right alignment.
Why does setting the alignment of the label to CENTER_RIGHT have no effect? I can see the API says: "Specifies how the text and graphic within the Labeled should be aligned when there is empty space within the Labeled." But how do I get empty space in a label?
TL:DR version: instead of label.setAlignment(Pos.CENTER_RIGHT); use GridPane.setHalignment(label, HPos.RIGHT);.
JavaFX uses a top-down layout. So the scene sizes the root node to the size of the scene, the root node sizes and positions each of its child nodes depending on its layout strategy and the amount of space the scene gave it, each child node then sizes and positions its child nodes depending on its own layout strategy and the amount of space it has available, and so on down the scene graph.
According to the documentation for Label, the alignmentProperty
Specifies how the text and graphic within the Labeled should be aligned when there is empty space within the Labeled.
Of course, the amount of space available to the label is determined by its parent, which in this case is the grid pane. You can of course find out about the grid pane's layout strategy and how to configure it by reading its documentation. In brief, though:
By default, a grid pane will allocate each node its preferred size, and, if the cell it's placed in has additional space, will align the node in the top left of the grid cell. The preferred size for a label is of course the computed size: just big enough to hold its content. Hence you see that simply placing a label into a grid pane and setting alignment on the label will not have any effect, because the label is sized just large enough to hold its content, and there is no extra space to align the text/graphic. You can visualize this by placing a background color or border on the label.
So you could set the alignment on the label to CENTER_RIGHT, and then instruct the grid pane to let the label grow. This needs two things: first, tell the grid pane to let the label fill the width of the cell:
GridPane.setFillWidth(label, true);
and, since the grid pane will also respect the child node's maximum size, and the label by default uses its preferred size as its maximum size, allow the label to grow:
label.setMaxWidth(Double.MAX_VALUE);
Then the label will grow to the size of the cell, and so if you also have
label.setAlignment(Pos.CENTER_RIGHT);
it will align its own content to the right.
A more sensible approach is probably just to tell the grid pane how to align the label in the cell:
GridPane.setHalignment(label, HPos.RIGHT);
Then let the label take on its default size and alignment and everything will work.
You can also use a ColumnConstraints object to set the default alignment for all labels in a particular column, which is by far the more convenient approach if you are building a form.

Accessing layout data from itemrenderer

I am working on a FLEX / AIR Spark list which lists a collection of images with differing width and height.
I am using a custom layout which works this way:
decide how many images can be fit in the current row based on their widths.
justify them in such a way that first image in the row obeys the "left" margin and the last image in the row obeys "right" margin, so with the "top" and "bottom" as specified by the user, let us say 10 pixels.
As an example, assuming that the current row has 4 images, the images 1 & 4 will have 10 pixels each as "left" margin "right" margin respectively. But the left and right gaps between 1-2, 2-3 & 3-4 will be equally divided based on the varying widths.
now i would like to draw a background that will fill the dynamic area. Please see the image below to get an idea:
Layout requirement Image
** In the image, The grey area is the background I would like to draw, and the colored rectangles represent images of differing widths and heights.**
the "rowHeight" is variable based on the maximum height of individual images within the row.
Issues:
a) Now I would like to draw a background (see the grey area in the pic) that fills the background area of the list. I know the current item's width & height, but I don't know the rowHeight decided by the layout, left and right margins between the images.
Something like:
bgRect:Rectangle = new rectangle ( 0, 0, (imgWidth + (LeftMargin/2) + (Right Margin/2) ), rowHeight)
b) How / where should the background be implemented? if i add the BG area within the item renderer based on the layout, again the layout will be relaid.
Children should be added in the createChildren method. Drawing (painting) the background should happen in updateDisplayList method.
You can pass data to your itemrenderers via an itemrenderer factory. See - Flex - Sending a parameter to a custom ItemRenderer?.
var productRenderer:ClassFactory = new ClassFactory(ProductRenderer);
productRenderer.properties = { showProductImage: true };
myList.itemRenderer = productRenderer;

Resizing the superview according to the subviews

I have 3 subviews(UILabel, UIImageview, UIButton) to be laid out on a container view. All the subviews are laid out using visual format language (VFL). The subview have padding from the leading , top edges etc. The content of the subview are dynamic so their sizes changes all the time. i want to resize the superview(container view) to exactly fit all the subviews. Is this possible by auto layout? i have seen some of the link here which suggest intrinsic size which i am not able to understand. can someone suggest a better way to achieve this.
Yes, it's possible. If you plan to resize the superview according to subview content, then intrinsic content size is the way to go.
The ever excellent Ray Wenderlich site has a tutorial that covers this well. It's Beginning Auto Layout in iOS 6: Part 2/2:
Intrinsic Content Size
Before Auto Layout, you always had to tell buttons and other controls
how big they should be, either by setting their frame or bounds
properties or by resizing them in Interface Builder. But it turns out
that most controls are perfectly capable of determining how much space
they need, based on their content.
A label knows how wide and tall it is because it knows the length of
the text that has been set on it, as well as the font size for that
text. Likewise for a button, which might combine the text with a
background image and some padding for the rounded corners.
The same is true for segmented controls, progress bars, and most other
controls, although some may only have a predetermined height but an
unknown width.
This is known as the intrinsic content size, and it is an important
concept in Auto Layout. You have already seen it in action with the
buttons. Auto Layout asks your controls how big they need to be and
lays out the screen based on that information.
It is possible.
In my case, I wanted to give rounded corners to segmented control. For that, I embedded segmented control in UIView. Now I was required to resize that container view as per size of segmented control.
I gave only following constraint and everything was taken care itself.
(1) Chose container view and give it X and Y constraints.
Leading space to Super view.
Top space to Super view.
(2) Chose container view and give Leading | Trailing | Top | Bottom constraint.
Leading space to segmented control.
Top space to segmented control.
Trailing space to segmented control.
Bottom space to segmented control.
(3) Chose segmented control and give it Height and Width constraints.
Height : 30 // Whatever
Width : 250 // Whatever
Now if I change the height and width of my segmented control, it automatically adjust container view's size (super-view of segmented control).

Resources