Custom width/height property for a widget are ignored - dart

Sometimes I want to force a widget to take a specific size, which I usually do by using a SizedBox/ConstrainedBox/Container
But I've realized that in some situations, the widget merely ignores it and takes a different size. Why is that?
Example:
Expected behavior:
Actual behavior:

This situation happens when the parent and its child wants two different sizes; but the parent has no idea how it should align its child within its boundaries.
The following code doesn't give enough information to tell how to align the red box within the blue box:
Container(
color: Colors.blue,
width: 42,
height: 42,
child: Container(
color: Colors.red,
width: 24,
height: 24,
),
),
So while it could be centered as such:
it would also be perfectly reasonable to expect the following alignment instead:
In that situation, since Flutter doesn't know how to align the red box, it will go with an easier solution:
Don't align the red box, and force it to take all the available space; which leads to:
To solve this issue, the solution is to explicitly tell Flutter how to align the child within its parent boundaries.
The most common solution is by wrapping the child into an Align widget:
Container(
color: Colors.blue,
width: 42,
height: 42,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.red,
width: 24,
height: 24,
),
),
),
Some widgets such as Container or Stack will also offer an alignment property to achieve similar behavior.

Related

Flutter FadeInImage Network - Will not fade in image on setState image change

I have a widget that uses FadeInImage.assetNetwork to load image, first time when the App loads, the image fade in of image works fine, while i try to update the Image URL state, the FadeInImage option doesn't work.
The Below widget is used to load the image, where qIcon is set dynamically on setState.
Widget quizIconCard(qIcon) {
return Card(
margin: EdgeInsets.all(5.0),
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
FadeInImage.assetNetwork(
height: 128,
width: 128,
placeholder: 'assets/login_logo.png',
image: qIcon,
imageScale: 1.2,
)
],
),
),
);
}
The setState for qIcon updates the image URL, but we do not see the fadeIn effect nor the placeholder image.
Any work around on this ?
The description of FadeInImage indicates that the fade only takes place once after the initial image loads, and any subsequent changes will just result in the image being replaced.
When either placeholder or image changes, this widget continues
showing the previously loaded image (if any) until the new image
provider provides a different image.
That means you will likely need to implement your image change in such a way that a new widget is generated instead of just changing the URL.

Why Flutter Container does not respects its width and height constraints when it is inside other Container

Container(
width: 200.0,
height: 200.0,
child: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red
),
),
)
I've been trying to find the answer in the Container class docs but I did not find it.
Update:
After a long time, I understood the problem.
All views inside a layout must have width, height, x position, and y position. (This applies to Android, IOS, Flutter, etc)
In my code, the inner container just has a width and height for that reason it doesn't know where to start painting.
For that reason, if the container is placed inside an Alignment widget the container gets the x position and y position and it works.
Constraints in Flutter works a bit different than usual.
Widgets themselves do not have constraints.
When you specify a width/height on a Container, you're not constraining Container. You're constraining the child of Container.
Container will then size itself based on the size of its child.
As such, parent widgets always have the last word on how their descendants should be sized.
If you want to go around this, you have to use Align widget:
Container(
width: 200.0,
height: 200.0,
child: Align(
alignment: Alignment.topLeft,
child: Container(
width: 50.0,
height: 50.0,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.red),
),
),
);
This may seem weird and limiting. But this single weirdness is the reason why Flutter's layout is so powerful and composable.
All views inside a layout must have four constraints:
Width
Height
X position
Y position
This applies to Android, IOS, Flutter, etc.
In the code, the inner container just has a width and height for that reason it doesn't know where to start painting and it gets all the available space.
But, if the inner container is placed inside another layout widget that aligns its child, for example, Center. It will get its x and y positions.
Container(
decoration : BoxDecoration(color : Colors.green),
width: 200.0,
height: 200.0,
child: Center(
child: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red
),
),
)
)
The inner container in red, the outer container in green.
Keep in mind, setting width or height of a container, it's same as setting min-width and max-width or min-height and max-height at the same time.
Your case for the inner Container according to the documentation will be:
If the widget has no child and no alignment, but a height, width, or constraints are provided, then the Container tries to be as small as possible given the combination of those constraints and the parent's constraints.
Since your outer container gives minWidth=minHeight=200 constraints to the inner container, thus the size of your inner container cannot be less than Size(200, 200).
In support of Rémi Rousselet's answer, the Align widget, same as Center widget, will expand to fit its parent's constraints, if its parent has constraints, and position its child in the specified alignment.
If the widget has an alignment, constraints, and the parent provides bounded constraints, then the Container tries to be as small as possible given the combination of those constraints and the parent’s constraints, and then positions the child within itself as per the alignment.
In this case, the outer Container has an Align widget as child (an alignment), constraints, and the parent provides bounded constraints, thus it tries to be as small as possible given the combination of its constraints and the parent’s constraints, which is Size(200, 200).
You might be wondering why does the inner Container has the size of 50*50, instead of 200*200, since its parent (outer Container) has specify the minWidth=minHeight = 200. The reason is that as mentioned before the Align widget will expand to fit its parent constraints, so in this case the Align widget will expand to fit the outer Container's constraints, i.e. it will have the size of Size(200, 200), and tell its child (the inner Container), that it can be any size it wants, but not bigger than my size, 200*200. Therefore, the information of minWidth and minHeight of the outer Container that is supposed to be pass to the inner Container is lost.
Some additonal information for the "Update" section of the question:
As metioned above,
All views inside a layout must have width, height, x position, and y position. (This applies to Android, IOS, Flutter, etc)
In my code, the inner container just has a width and height for that reason it doesn't know where to start painting.
The reason why the inner container doesn't know where to start painting is that its parent, which is the outer Container Widget, does not have a corresponding RenderObject(it doesn't implement a createRenderObject method), hence which can't performLayout alone, and here comes the big deal:
Most widgets set the offset of their children(the x, and the y position of the children) by putting the Offset data in the parentData attributes in them, and such process is done in the performLayout method, so in the nested Container usage scanarios, the inner container can't get a reasonable offset from the outer widget, and therefore setting the width and height fails working in the inner container.
Furthermore, why Align Widget can help solving this problem?
Take a glimpse of the Align source code and everything becomes clear and plain
// Align -> createRenderObject -> RenderPositionedBox -> alignChild
#protected
void alignChild() {
// ....irrelevant code
final BoxParentData childParentData = child!.parentData! as BoxParentData;
childParentData.offset = _resolvedAlignment!.alongOffset(size - child!.size as Offset);
}
And I sure believe any other Widgets similar to Align Widget that set the offset of their children can solve this problem as well

Align Text of different size in row to bottom

I have a row where the children are 2 Texts. The first is fontsize 20 and the second is size 13. I'm trying to align both to bottom but so far no luck. It's like the first large one gets some additional padding.
Any good hints on how to align the two Text?
I think you need to play around with the crossAxisAlignment and textBaseline properties of your Row widget.
Try something like this:
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text("foo", style: TextStyle(fontSize: 20)),
Text("bar", style: TextStyle(fontSize: 13)),
],
),

Show paragraph with ellipsis in Flutter

I know how to use ellipsis with the Text widget. overflow: TextOverflow.ellipsis does the job very well. But my problem is it actually displays only one line. I am trying to make a layout something similar to the below image:
How to do this in Flutter?
It is a common layout and it is sad that it isn't documented anywhere :(
use overflow in addition to maxlines. if you need to adhere to a really tight fixed height then you can easily calculate what maxlines should be based upon your font size.
Text(
'my super long string',
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
maxLines: 3,
),

Flutter overflow: hidden analogue

Is there any flutter widget that prevents the children to paint outside a Container by any mean?
I have this container with a child that may get some transformations (such as scale and rotate) and therefore can be painted outside
I want to limit the children's painting to only inside the parent Container, just like a div with CSS overflow:hidden; would behave.
A sample:
return Container( // the one with overflow hidden -ish behavior
height: 300.0,
child: TheTransformingChild() // the one that can get bigger that container
)
I think it's easier to use clipBehavior: property in container
Container(
clipBehavior: Clip.hardEdge,
height: 400,
width: 400,
child :TheTransformingChild(),)
There is - what you're looking for is a combination of OverflowBox or SizedOverflowBox and ClipRect, or ClipOval, or ClipPath, or ClipRRect etc.
I'd recommend looking through the painting and layout sections of the flutter widget catalog (and the rest of it as well) as it generally does a pretty good job of showcasing the widgets you need.
An easy way is to use the Wrap component (below is your example).
return Container( // the one with overflow hidden -ish behavior
height: 300.0,
child: Wrap(
children: [
TheTransformingChild()
],
)
)
It also replaces the Column component in most cases:
Using Column
Using Wrap

Resources