-
Notifications
You must be signed in to change notification settings - Fork 0
Layout
LayoutConstraints is a value struct that describes the minimum and maximum size a
RenderObject is allowed to be.
public struct LayoutConstraints
{
public float MinWidth, MaxWidth, MinHeight, MaxHeight;
}| Factory | Meaning |
|---|---|
LayoutConstraints.Tight(w, h) |
min == max — forces exact size |
LayoutConstraints.Loose(maxW, maxH) |
min == 0 — child can be any size up to max |
LayoutConstraints.TightFor(width?, height?) |
Tight on specified axes, infinite on others |
constraints.Loosen() |
Zero the minimums, keep the maximums |
constraints.Enforce(other) |
Intersect two constraint ranges |
constraints.Constrain(size) |
Clamp a Vector2 to the box |
Each RenderObject.PerformLayout() decides what constraints to pass to its children. The root
receives constraints based on the WindowConfig: Tight(windowSize) for fixed-size windows,
or Loose(screenWidth, screenHeight) for shrink-wrap windows. Children receive constraints
derived from the parent's own constraints minus any padding, borders, or fixed sizes.
A child cannot exceed the MaxWidth/MaxHeight it receives. A child that reports a size
smaller than MinWidth/MinHeight will be clamped up by Layout() after PerformLayout().
Row and Column implement a flexbox algorithm. Both use RenderFlex internally.
// Row — horizontal flex
new Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.SpaceBetween,
crossAxisAlignment: CrossAxisAlignment.Center,
children: [ ... ]
)
// Column — vertical flex
new Column(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.Start,
crossAxisAlignment: CrossAxisAlignment.Stretch,
children: [ ... ]
)Controls how children are distributed along the main axis (horizontal for Row, vertical for Column) after all children have been sized.
| Value | Behavior |
|---|---|
Start |
Pack children to the start edge |
End |
Pack children to the end edge |
Center |
Center children as a group |
SpaceBetween |
First/last children at edges; equal gaps between |
SpaceAround |
Equal gaps around each child (half gap at edges) |
SpaceEvenly |
Equal gaps between all children and at edges |
Controls child positioning on the perpendicular axis.
| Value | Behavior |
|---|---|
Start |
Align to the start edge of the cross axis |
Center |
Center on the cross axis |
End |
Align to the end edge of the cross axis |
Stretch |
Force child to fill the full cross-axis extent |
Controls how much main-axis space the container itself occupies.
| Value | Behavior |
|---|---|
Max (default)
|
Container fills all available main-axis space |
Min |
Container shrinks to the total size of its children |
// Shrink-wrap: Row is exactly as wide as its children + spacing
new Row(
mainAxisSize: MainAxisSize.Min,
children: [ new Icon("star"), new Text("Label") ]
)
// Fill: Row stretches to the full width it was given (default)
new Row(
mainAxisSize: MainAxisSize.Max,
children: [ new Text("Left"), new Text("Right") ]
)Note:
MainAxisSizeonly has a visible effect when the container has noExpandedchildren. WhenExpandedchildren are present,MainAxisSize.Maxforces the container to claim the full available space (so flex fractions are computed correctly), whileMainAxisSize.Minmakes the container report the actual consumed size instead.
Expanded tells its flex parent to give it all remaining main-axis space after fixed children
are sized. Multiple Expanded children share space proportionally via their flex factor:
new Row(children:
[
new Text("Label"), // fixed width
new Expanded( // gets 2/3 of remaining space
flex: 2,
child: new TextField()
),
new Expanded( // gets 1/3 of remaining space
flex: 1,
child: new NumericField()
),
])Expanded only works as a direct child of Row or Column. Using it elsewhere has no
effect.
-
Fixed pass — all non-
Expandedchildren are laid out with the full cross-axis constraint (or tight cross ifStretch). Their main-axis sizes are accumulated. -
Flex pass — remaining main-axis space is divided among
Expandedchildren by flex factor. -
Position pass — children are placed using
MainAxisAlignmentandCrossAxisAlignment.
Stack layers children on top of each other. Unpositioned children are placed at (0, 0) and
the stack's size is determined by their bounding box. Positioned children are placed
absolutely using offset values.
new Stack(
[
// Unpositioned — fills the stack (or sizes naturally)
new Container(style: new BoxStyle { Color = new Vector4(0.1f, 0.1f, 0.1f, 1) }),
// Positioned — 10px from left, 20px from top, 100px wide
new Positioned(
left: 10, top: 20, width: 100,
child: new Text("Overlay label")
),
// Positioned from the right edge
new Positioned(
right: 8, top: 8,
child: new CloseButton()
),
])Positioned only has meaning as a direct child of Stack. It stores its offset values in
StackParentData on its child's RenderObject.
- If all children are positioned, the stack sizes itself to its own parent's constraints (fills available space).
- If there are any unpositioned children, the stack sizes to their combined bounding box, then positioned children are placed relative to that size.
// Fixed-size box
new SizedBox(width: 200, height: 50, child: new Text("..."))
// Spacer in a Row/Column
new SizedBox(width: 16) // horizontal spacer
new SizedBox(height: 8) // vertical spacerIf both width and height are null, SizedBox is equivalent to a transparent Container
that sizes to its child.
new Container(
style: new BoxStyle
{
Width = 300, // fixed width (optional)
Height = 200, // fixed height (optional)
Padding = EdgeInsets.All(16),
Color = new Vector4(0.1f, 0.1f, 0.1f, 0.9f),
CornerRadius = new Vector4(8),
BorderThickness = 1,
BorderColor = new Vector4(1, 1, 1, 0.3f),
ClipBehavior = ClipBehavior.AntiAlias,
},
child: new Text("Content")
)Container internally composes Padding + a constrained box. When Width/Height are set,
it imposes tight constraints on its child via RenderConstrainedBox.
CornerRadius is a Vector4 where each component maps to a corner:
| Component | Corner |
|---|---|
X |
Top-right |
Y |
Bottom-right |
Z |
Top-left |
W |
Bottom-left |
Use new Vector4(r) to set all corners uniformly to radius r.
new Padding(EdgeInsets.All(16), child: new Text("Padded"))EdgeInsets factory methods:
EdgeInsets.All(16) // 16px on all sides
EdgeInsets.Only(left: 8, top: 4, right: 8, bottom: 4)
EdgeInsets.Symmetric(vertical: 12, horizontal: 20)
EdgeInsets.Ltrb(left, top, right, bottom)
EdgeInsets.Zero // no paddingAlign positions a child at any point within its parent using a normalized coordinate system
where (-1, -1) is top-left and (1, 1) is bottom-right:
new Align(alignment: Alignment.Center, child: myWidget)
new Align(alignment: Alignment.BottomRight, child: myWidget)
new Align(alignment: new Alignment(0, -0.5f), child: myWidget) // customCenter is shorthand for Align(Alignment.Center):
new Center(child: myWidget)Align sizes itself to fill its parent when the parent provides finite constraints. When
infinite space is available (e.g., inside a scroll view), it sizes to the child.
TopLeft, TopCenter, TopRight, CenterLeft, Center, CenterRight, BottomLeft,
BottomCenter, BottomRight.
ClipBehavior can be set on any Container (via BoxStyle.ClipBehavior) or applied
explicitly with the Clip widget:
new Clip(
borderRadius: new Vector4(12), // all corners
child: new Image("domain", "path/image.png", fit: BoxFit.Cover)
)ClipBehavior |
Behavior |
|---|---|
None |
No clipping (default) |
HardEdge |
Clip to rect; no anti-aliasing on clip edge |
AntiAlias |
Clip to rounded rect with anti-aliased edge |