SideBySide constructor
- Key? key,
- List<
Widget> children = const [], - @Deprecated('Use the `children` property instead.') Widget? startChild,
- @Deprecated('Use the `children` property instead.') Widget? endChild,
- List<
double> gaps = const [], - CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
- TextDirection textDirection = TextDirection.ltr,
- @Deprecated('Use the `gaps` property instead.') double innerDistance = 0,
- double minEndChildWidth = 0,
- MainAxisSize mainAxisSize = MainAxisSize.max,
The SideBySide widget arranges its children widgets horizontally, achieving a
layout that is not possible with Row or RowSuper widgets.
The first widget in children will be on the left, and will occupy as much
horizontal space as it wants, up to the available horizontal space. Then, the
next widget will be displayed to the right of the previous widget, and so on,
one by one, until they run out of available space. After the available space
is occupied, the widgets that did not fit will not be displayed (or, more
precisely, will be sized as 0 width).
Why this layout is not possible with Row?
Suppose you want to display two texts is a row, such as they occupy the
available space: Row(children: [Text("One"), Text("Two")]). If the available
horizontal space is not enough, the texts will overflow. You can fix this by
wrapping the texts in Expanded widgets, but then they will each occupy half of
the available space. If instead you use Flexible to wrap the texts, they will
occupy the available space only if there is enough space for both of them,
otherwise they will each occupy half of the available space.
If instead you use SideBySide(children: [Text("One"), Text("Two")]), the first
text will occupy as much space as it wants, and the second text will occupy the
remaining space, if there is any.
The last widget
The last widget in children is an is a special case, for two reasons. First,
it will be given all the remaining horizontal space, after the previous widgets
have been displayed. This means you can align it to the right if you want:
SideBySide(
children: [
const Text("Some text", textWidthBasis: TextWidthBasis.longestLine),
Align(
alignment: Alignment.centerRight,
child: const Text("more text", textWidthBasis: TextWidthBasis.longestLine),
),
],
);
Second, you can specify the minimum width that it should occupy, using
the minEndChildWidth property. This means that the last widget will occupy
AT LEAST that width, even if it means that the previous widgets will be pushed out
of the available space. However, if the total available space is less
than minEndChildWidth, then the last widget will be displayed only up to the
available space.
Gaps
You can add gaps between the widgets, using the gaps property. The gaps are
a list of doubles representing pixels. If you have two children, you should
provide one gap. If you have three children, you should provide two gaps, and so on.
Note the gaps can be negative, in which case the widgets will overlap.
If you provide less than the required number of gaps, the last gap will be used for all the remaining widgets. If you provide more gaps than required, the extra gaps will be ignored.
Cross alignment and main axis size
The crossAxisAlignment property specifies how to align the widgets vertically.
The default is to center them. At the moment, only CrossAxisAlignment.start,
CrossAxisAlignment.end and CrossAxisAlignment.center work. If you provide
CrossAxisAlignment.baseline or CrossAxisAlignment.stretch, you'll get
an UnimplementedError.
The mainAxisSize property determines whether the widget will occupy the full
available width (MainAxisSize.max) or only as much as it needs (MainAxisSize.min).
Using Text as children
When you use Text widgets in your children, it's strongly recommended that
you use property textWidthBasis: TextWidthBasis.longestLine. The default
textWidthBasis is usually textWidthBasis: TextWidthBasis.parent, which
is almost never what you want. For example, instead of writing:
Text("Hello"), you should write:
Text("Hello", textWidthBasis: TextWidthBasis.longestLine).
Examples
Suppose you want to create a title aligned to the left, with a divider that occupies the rest of the space. You want the distance between the title and the divider to be at least 8 pixels, and you want the divider to occupy at least 20 pixels of horizontal space:
return SideBySide(
children: [
Text("First Chapter", textWidthBasis: TextWidthBasis.longestLine),
Divider(color: Colors.grey),
],
gaps: [8.0],
minEndChildWidth: 20.0,
);
Another example, with 3 widgets:
return SideBySide(
children: [
Text("Hello!", textWidthBasis: TextWidthBasis.longestLine),
Text("How are you?", textWidthBasis: TextWidthBasis.longestLine),
Text("I'm good, thank you.", textWidthBasis: TextWidthBasis.longestLine),
],
gaps: [8.0, 12.0],
);
Deprecated usage
The startChild and endChild properties are deprecated. Use the children
property instead. The innerDistance property is also deprecated. Use the gaps
property instead.
For example, this deprecated code:
return SideBySide(
startChild: Text("Hello!", textWidthBasis: TextWidthBasis.longestLine),
endChild: Text("How are you?", textWidthBasis: TextWidthBasis.longestLine),
innerDistance: 8.0,
);
Should be replaced with:
return SideBySide(
children: [
Text("Hello!", textWidthBasis: TextWidthBasis.longestLine),
Text("How are you?", textWidthBasis: TextWidthBasis.longestLine),
],
gaps: [8.0],
);
For more info, see: https://pub.dartlang.org/packages/assorted_layout_widgets
Implementation
factory SideBySide({
Key? key,
List<Widget> children = const [],
//
@Deprecated('Use the `children` property instead.') Widget? startChild,
//
@Deprecated('Use the `children` property instead.') Widget? endChild,
//
List<double> gaps = const [],
//
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
//
TextDirection textDirection = TextDirection.ltr,
//
@Deprecated('Use the `gaps` property instead.') double innerDistance = 0,
//
double minEndChildWidth = 0,
//
MainAxisSize mainAxisSize = MainAxisSize.max,
//
}) {
// 1) Deprecated usage.
if (startChild != null && endChild != null) {
//
if (children.isNotEmpty)
throw ArgumentError(
'Cannot use `startChild` and `endChild` with the `children` property.');
if (gaps.isNotEmpty)
throw ArgumentError('Cannot use `gaps` with the `startChild` property.');
return SideBySide._(
key: key,
startChild: startChild,
endChild: endChild,
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection,
innerDistance: innerDistance,
minEndChildWidth: minEndChildWidth,
mainAxisSize: mainAxisSize,
);
}
if (startChild != null && endChild == null)
throw ArgumentError(
'If you provide `startChild` you should also provide `endChild`. '
'However, it is better to provide only `children` instead, '
'as `startChild` and `endChild` are deprecated.');
if (startChild == null && endChild != null)
throw ArgumentError(
'If you provide `endChild` you should also provide `startChild`. '
'However, it is better to provide only `children` instead, '
'as `startChild` and `endChild` are deprecated.');
// 2) Empty usage.
if (children.isEmpty)
return SideBySide._(
key: key,
startChild: const SizedBox(),
endChild: const SizedBox(),
textDirection: textDirection,
mainAxisSize: mainAxisSize,
);
// 3) When providing [children], can't use `startChild` or `endChild`.
if (startChild != null || endChild != null)
throw ArgumentError(
'Cannot use `startChild` or `endChild` with the `children` property.');
if (innerDistance != 0)
throw ArgumentError('Cannot use `innerDistance` with the `children` property. '
'Use `gaps` instead.');
// 4) A single child.
if (children.length == 1)
return SideBySide._(
key: key,
startChild: children[0],
endChild: const SizedBox(),
textDirection: textDirection,
);
Widget nestedSideBySide = children.last;
// Create something like: s(1, s(2,3))
for (int i = children.length - 2; i >= 0; i--) {
nestedSideBySide = SideBySide._(
key: key,
startChild: children[i],
endChild: nestedSideBySide,
crossAxisAlignment: crossAxisAlignment,
minEndChildWidth: minEndChildWidth,
innerDistance: (innerDistance +
(gaps.isNotEmpty //
? (i < gaps.length ? gaps[i] : gaps.last) //
: 0)),
textDirection: textDirection,
mainAxisSize: mainAxisSize,
);
}
return nestedSideBySide as SideBySide;
}