Autoresize Text to fit in Container vertically - dart

I want to create an app, that shows sometimes shorter, somertimes longer text in a Container. This container should not change in size, after the widget is build to fit with the size of the screen. The text itself comes from a database and I don't know, how long it can be.
When I print the text in the container, sometimes it fits, sometimes there is many space above and below, when the text is short, or sometime the text overflows and is not visible.
I want, that the text size is automatically changed to fit into the container. Container with overflow
The flutter package Auto-Size-Text is not working for me, because I only could resize the text to fit the width or set the maximum line, which I don't know either.
This is my code simplified:
AutoSizeText autotext = AutoSizeText(text, style: style, textAlign: TextAlign.center, presetFontSizes: [25.0,22.0,20.0,18.0], semanticsLabel: text);
Container(
child: autotext
);

TL;DR:
Your AutoSizeText widget is probably provided with unbounded constraints.
This can be the case if it's wrapped in a Column, Row, ListView or something similar.
To counter this issue, wrap it in an Expanded widget.
In order to answer that question, we need to understand how Flutter performs the layout.
Basically, the top widget's height and width (called its "dimensions") are requested by the framework, which provides a min and max width and height (called "constraints").
In order to calculate its dimensions, the widgets ask their children what dimensions they want to have based on some constraints.
So, every widget gets told constraints and returns concrete dimensions within these constraints.
Widgets like ListView or Column don't want to influence their children's dimensions too much - they should simply be as small as possible.
In order to communicate that, they are given a maximum width/height of double.infinity, telling them that they should default to their "natural"/default dimensions. A constraint of this type is called "unbounded".
Here's a Google Tech Talk video about Flutter's rendering pipeline, where all of this is described in greater detail.
With this process in mind, let's have a look at how your widgets perform during layout:
In a comment to your post, you said there's a Column widget, so I assume there's a Column containing a Container, which in turn contains the AutoSizeText widget.
If instead of a Column, there's a Row or ListView or something similar, the process is basically the same.
The Column wants its children to be as small as possible, so it passes unbounded constraints to all of its children.
Being one of those children, the Container receives those unbounded constraints.
Because the Container itself is just a wrapper class, it simply passes these constraints on to its child, the AutoSizeText.
The AutoSizeText receives unbounded constraints.
Looking at its source code, we can see that it starts with a default text size and checks if it fits (calling _checkTextFits).
If it doesn't fit, the text size is decreased and this process is repeated until the text is small enough to fit into the given constraints.
Because in your case, the constraints are unbound, the text fits on the first try - that means the widget simply uses the default size.
Having determined the text size, it can calculate the text's dimensions and returns them up the tree.
The Container receives those dimensions.
Because it's just a wrapper class, it simply returns them to its parent in turn.
Finally, the Column receives the dimensions and sizes itself around that (probably adding the dimensions of other children).
Solution
You don't want to pass unbounded constraints to an AutoSizeText widget, because that defeats the purpose of the widget in the first place - fitting text into bounded constraints.
You can confirm this is the problem by hardcoding the Container's width and height, that should make the AutoSizeText widget adjust the text size properly.
If the Container is placed inside a Column or something similar, you can always bound the constraints by wrapping it in an Expanded.
Why the solution works
The Column checks which of its children are Expanded widgets.
It first lays out all the other widgets.
Only then, it divides the remaining space among the Expanded widgets according to their flex factors (that's a whole other topic for itself).
That means the Expandeds' children will receive bounded constraints.
If you wrap your Container in an Expanded and it's the only expanded in the Column, it should take all the remaining space, and fit the text perfectly within itself.

Related

Content of Grid list to fill the height

I am placing content in the grid list component and I want the grid tile to grow accordingly to the content it has. I tried to use rowHeight="fit" as documentation states but it doesn't seems to work.
Here an example
MatGridList overall size is directly related to the rowHeight setting. The default rowHeight value is a ratio 1:1 (which means column width equals row height).
When you use a ratio, the list will have a fixed width/height ratio overall, so if the list can't grow in one direction because of window or layout restrictions, it can't grow in any direction. This is why your example looks the way it does. If you expand the width of the window, you'll see the list expand vertically as well. You can set a different rowHeight value to make the tiles taller than wide such as rowHeight="1:2" (that seems backwards to me but that's how it works).
When you use rowHeight="fit", this doesn't fit the list to the content, it fits the row heights to the list height, but as noted in the documentation, you must set a height on the list or a parent for this to work properly.
Setting a fixed value for rowHeight does what it sounds like.

Fitting multi-line text into a dynamically size-changing node

A multiline auto typing text box class (which uses an SKNode as the parent) is created using basically 2 elements:
an SKSpriteNode that acts as text box frame & background image/texture holder.
an NSMutableArray containing a set limited amount (rows) of NSStrings that each have a set character length.
After modifying this text box class so that it can be initialized with any frame width & height, I realized I didn't program the NSMutableArray to automatically change its content in a such way that it nicely fits within the background node (with a bit of padding involved as well). So here I am wondering how to do that since NSString's can only return the character count and not the width & height of each string in points (points could have maybe helped me create character constraints in some way).
Right now, the NSMutableArray uses a hardcoded maximum character count per NSString & a maximum row count for the entire array (it's 5 rows right now and when that limit is reached, a new "page"/array is created). This forces me to manually re-adjust these parameters every time I change the background node frame size which defeats the purpose of the class allowing the background frame to change.
Thing is, I'm trying to solve this in such a way that when I post this class on github, I want the solution to take into consideration any fontName & fontSize.
What are my options for solving this problem?
I've done something similar to this. It doesn't work 100% as to what you want, but should be similar enough. It uses a root node and from there, it will build multi-line text using an array of NSString which will in turn be used to build the SKLabelNode.
I'll outline what I did. I should also say I only run this when new text is set. In other words, I do not incur the penalty of deriving the information every frame. Only once.
The generalized steps are:
You will iterate over each character in the text string. Note I do this because my code supports word wrapping as well as other alignment capabilities. So for me, I want that level of control. As this is being done only upon creation, I'm fine with the overhead. If you don't want to word wrap you could always just create an array of words and work from there.
As you iterate over each character, you'll be generating an array of lines. Where each line in the array is a line that will fit in your frame. For now let's not worry about vertical constraints. So here we are primarily worried about width. For the current line, each character you are iterating over will get added to the current line. For this potential line string, you will use NSString's sizeWithAttributes, which is configured for your font. For example in my code it is an NSDictionary which contains: NSFontAttributeName : [UIFont fontWithName:self.fontName size:self.size]. This will be used to check the width, if that width exceeds the frame width, you are overrunning the line.
So the code may look something like:
size = [line sizeWithAttributes:attributes];
if (size.width > maxTextWidth) {
needNewline = YES;
}
If you have overrun a line, you need to determine if you are word wrapping. If you are, you can just add the current line (minus one character) to the lines array. If not you have prune off the last word in the current line and then add that to the array of lines.
The tricky parts are dealing with whitespace and handling non-word wrapped overflow. I have not addressed whitespace but you need to consider this very much in your code. Additionally, you also do want to factor in leading pixels, etc.
Once you have your array of lines, you can then create your children SKLabelNodes. I add them to the root, which allows me to move the group anywhere it needs to be.
The real key here is the lines array generation.

(Auto Fit All Columns) of ListGrid's Context Menu stretches the Row number in SmartGWT

I'm not sure whether this should be the expected behaviour or is a bug.
When the Row Number column is set to be shown, selection of (Auto Fit All Columns) from context menu stretches the column
to the end of the ListGrid.
I though there is an issue in our app but the ShowCase has (Grids > Appearance > Row Numbering)
the same problem.
final ListGrid countryGrid = new ListGrid();
countryGrid.setWidth(500);
countryGrid.setHeight(224);
countryGrid.setShowAllRecords(true);
countryGrid.setShowRowNumbers(true);
If you change the width of a column before applying the Auto fit it behaves normally.
Has someone had the same issue ever?
Is there any workaround?
Without looking further at your code (for instance, other width and autofit related configurations applied to the list grid, field types and expected contents) it's difficult to know if this is expected behavior. Although I agree, by looking at the demo, that it is at least strange behavior.
But this is what I do in my ListGrids to keep the row numbers at the size I want:
// this field is created only as a way to define the row number field properties
ListGridField rowNumberFieldProps = new ListGridField();
rowNumberFieldProps.setWidth(50);
rowNumberFieldProps.setCanAutoFitWidth(true);
rowNumberFieldProps.setAutoFitWidthApproach(AutoFitWidthApproach.VALUE);
grid.setRowNumberFieldProperties(rowNumberFieldProps);
grid.setShowRowNumbers(true);
Some notes:
Since I expect a lot of records to be displayed (and in consequence, large row numbers), I use a row number column width that fits properly my numbers (50 in my case).
Notice that setCanAutoFitWidth(false) will leave your row number field fixed in size, even when 'Auto Fit All Columns' is used. This is probably a good approach in your case. If you do that, you can simply remove the line with setAutoFitWidthApproach.
setCanAutoFitWidth(true) and setAutoFitWidthApproach help me control what happens when I use the 'Auto Fit All Columns' context menu. In my case I do want autofitting to apply to extend the column width when I have row numbers beyond 99.999 (not the most common case for me, but possible).

Spacing In VLayout

I am working inside a Tabpane and I want to have 2 buttons on the bottom-right of the tap-pane, so I thought I just add a LayoutSpacer, but this resulted in
but I wanted it to look like
How can I make my Layoutspacer "bigger"?
In Smart GWT there are different methods to set the size of the component's vertical dimension.
Try with any one
canvas.setHeight100()
canvas.setHeight("100%")
canvas.setHeight("*")
Layouts may specially interpret percentage sizes on their children, and also allow "*" as a size.

How do I make a TCheckListBox scroll vertically?

I've got a TCheckListBox on a form. Its Columns property is set to 2, and if there are more items than can fit on-screen in two columns, it puts a horizontal scrollbar across the bottom of the control.
Thing is, the way this form it laid out, it would be much more convenient to scroll vertically. But I can't seem to figure out how to make the box do that. I thought setting Columns to 1 should work, but it doesn't.
Anyone know how to make a TCheckListBox scroll vertically instead of horizontally?
You need to set Columns to 0.
For all positive values the VCL sends a LB_SETCOLUMNWIDTH message to the underlying native list box control, with the width parameter set to the list box client width divided by the number of columns. Items that don't fit will start a new column with the same column width, so the horizontal scrollbar becomes visible.
If Columns is 0 then there is a single column that spans the entire client width of the list box, and items that don't fit will make the vertical scrollbar visible, and hide the horizontal scrollbar.
Edit:
There seems to be genuine interest what happens when a negative value is used for the Columns property.
The method TCustomListBox.CreateParams() sets the LBS_MULTICOLUMN list box style depending on the Columns property being different from 0. For negative values the style flag is set, but the VCL doesn't send the LB_SETCOLUMNWIDTH message, so the native control uses the default column width. It is documented to be:
15 times the average character width for the font used by the list box.
(Search for "The LBS_MULTICOLUMN style specifies" to find the relevant passage of text.)

Resources