[Reland] Introduce double
Flex.spacing
parameter for Row
/Column
spacing (#152890)
Relands https://github.com/flutter/flutter/pull/152472 (Fixed error causing message test, maybe by https://github.com/flutter/flutter/pull/152501) --- fixes [add spacing parameter to Column and Row](https://github.com/flutter/flutter/issues/55378) ### `Column.spacing` Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( backgroundColor: Colors.black, body: Center( child: Padding( padding: const EdgeInsets.all(16.0), child: DecoratedBox( decoration: BoxDecoration( border: Border.all( color: Colors.amber, )), child: const Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Column( spacing: 40.0, // ignore: avoid_redundant_argument_values mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Column( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Column( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Column( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Column( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Column( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.topCenter, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.bottomCenter, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), ], ), ), ), ), ), ); } } ``` </details> ### Preview <img width="1072" alt="Screenshot 2024-07-30 at 15 40 59" src="https://github.com/user-attachments/assets/14f21091-9e46-4a58-8552-1379f4ba9216"> ### `Row.spacing` Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( backgroundColor: Colors.black, body: Center( child: Padding( padding: const EdgeInsets.all(16.0), child: DecoratedBox( decoration: BoxDecoration( border: Border.all( color: Colors.amber, )), child: const Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Row( spacing: 40.0, // ignore: avoid_redundant_argument_values mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerRight, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Row( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerRight, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Row( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerRight, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Row( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerRight, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Row( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerRight, child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), Row( spacing: 40.0, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ ColoredBox( color: Color(0xffff0000), child: SizedBox( width: 50.0, height: 75.0, child: Align( alignment: Alignment.centerLeft, child: Text( 'RED', style: TextStyle(color: Colors.white), ), ), ), ), ColoredBox( color: Color(0xff00ff00), child: SizedBox( width: 50.0, height: 75.0, child: Center( child: Text( 'GREEN', style: TextStyle(color: Colors.black), ), ), ), ), ColoredBox( color: Color(0xff0000ff), child: SizedBox( width: 50.0, height: 75.0, child: Align( child: Text( 'BLUE', style: TextStyle(color: Colors.white), ), ), ), ), ], ), ], ), ), ), ), ), ); } } ``` </details> ### Preview <img width="1072" alt="Screenshot 2024-07-30 at 15 39 42" src="https://github.com/user-attachments/assets/717e9f5e-a491-4853-ba74-e72ec7493363">
This commit is contained in:
parent
173bf86b7b
commit
00ef750d28
@ -215,19 +215,19 @@ enum MainAxisAlignment {
|
|||||||
/// after the first and last child.
|
/// after the first and last child.
|
||||||
spaceEvenly;
|
spaceEvenly;
|
||||||
|
|
||||||
(double leadingSpace, double betweenSpace) _distributeSpace(double freeSpace, int itemCount, bool flipped) {
|
(double leadingSpace, double betweenSpace) _distributeSpace(double freeSpace, int itemCount, bool flipped, double spacing) {
|
||||||
assert(itemCount >= 0);
|
assert(itemCount >= 0);
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
MainAxisAlignment.start => flipped ? (freeSpace, 0.0) : (0.0, 0.0),
|
MainAxisAlignment.start => flipped ? (freeSpace, spacing) : (0.0, spacing),
|
||||||
|
|
||||||
MainAxisAlignment.end => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, !flipped),
|
MainAxisAlignment.end => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, !flipped, spacing),
|
||||||
MainAxisAlignment.spaceBetween when itemCount < 2 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped),
|
MainAxisAlignment.spaceBetween when itemCount < 2 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped, spacing),
|
||||||
MainAxisAlignment.spaceAround when itemCount == 0 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped),
|
MainAxisAlignment.spaceAround when itemCount == 0 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped, spacing),
|
||||||
|
|
||||||
MainAxisAlignment.center => (freeSpace / 2.0, 0.0),
|
MainAxisAlignment.center => (freeSpace / 2.0, spacing),
|
||||||
MainAxisAlignment.spaceBetween => (0.0, freeSpace / (itemCount - 1)),
|
MainAxisAlignment.spaceBetween => (0.0, freeSpace / (itemCount - 1) + spacing),
|
||||||
MainAxisAlignment.spaceAround => (freeSpace / itemCount / 2, freeSpace / itemCount),
|
MainAxisAlignment.spaceAround => (freeSpace / itemCount / 2, freeSpace / itemCount + spacing),
|
||||||
MainAxisAlignment.spaceEvenly => (freeSpace / (itemCount + 1), freeSpace / (itemCount + 1)),
|
MainAxisAlignment.spaceEvenly => (freeSpace / (itemCount + 1), freeSpace / (itemCount + 1) + spacing),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,6 +390,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
VerticalDirection verticalDirection = VerticalDirection.down,
|
VerticalDirection verticalDirection = VerticalDirection.down,
|
||||||
TextBaseline? textBaseline,
|
TextBaseline? textBaseline,
|
||||||
Clip clipBehavior = Clip.none,
|
Clip clipBehavior = Clip.none,
|
||||||
|
double spacing = 0.0,
|
||||||
}) : _direction = direction,
|
}) : _direction = direction,
|
||||||
_mainAxisAlignment = mainAxisAlignment,
|
_mainAxisAlignment = mainAxisAlignment,
|
||||||
_mainAxisSize = mainAxisSize,
|
_mainAxisSize = mainAxisSize,
|
||||||
@ -397,7 +398,9 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
_textDirection = textDirection,
|
_textDirection = textDirection,
|
||||||
_verticalDirection = verticalDirection,
|
_verticalDirection = verticalDirection,
|
||||||
_textBaseline = textBaseline,
|
_textBaseline = textBaseline,
|
||||||
_clipBehavior = clipBehavior {
|
_clipBehavior = clipBehavior,
|
||||||
|
_spacing = spacing,
|
||||||
|
assert(spacing >= 0.0) {
|
||||||
addAll(children);
|
addAll(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,6 +591,69 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@template flutter.rendering.RenderFlex.spacing}
|
||||||
|
/// How much space to place between children in the main axis.
|
||||||
|
///
|
||||||
|
/// The spacing is only applied between children in the main axis.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is
|
||||||
|
/// [MainAxisAlignment.start], then the first child will be placed at the start
|
||||||
|
/// of the main axis, and the second child will be placed 10.0 pixels after
|
||||||
|
/// the first child in the main axis, and so on. The [spacing] is not applied
|
||||||
|
/// before the first child or after the last child.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.end],
|
||||||
|
/// then the last child will be placed at the end of the main axis, and the
|
||||||
|
/// second-to-last child will be placed 10.0 pixels before the last child in
|
||||||
|
/// the main axis, and so on. The [spacing] is not applied before the first
|
||||||
|
/// child or after the last child.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.center],
|
||||||
|
/// then the children will be placed in the center of the main axis with 10.0
|
||||||
|
/// pixels of space between the children. The [spacing] is not applied before the first
|
||||||
|
/// child or after the last child.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceBetween],
|
||||||
|
/// then there will be a minimum of 10.0 pixels of space between each child in the
|
||||||
|
/// main axis. If the free space is 100.0 pixels between the two children,
|
||||||
|
/// then the minimum space between the children will be 10.0 pixels and the
|
||||||
|
/// remaining 90.0 pixels will be the free space between the children. The
|
||||||
|
/// [spacing] is not applied before the first child or after the last child.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceAround],
|
||||||
|
/// then there will be a minimum of 10.0 pixels of space between each child in the
|
||||||
|
/// main axis, and the remaining free space will be placed between the children as
|
||||||
|
/// well as before the first child and after the last child. The [spacing] is
|
||||||
|
/// not applied before the first child or after the last child.
|
||||||
|
///
|
||||||
|
/// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceEvenly],
|
||||||
|
/// then there will be a minimum of 10.0 pixels of space between each child in the
|
||||||
|
/// main axis, and the remaining free space will be evenly placed between the
|
||||||
|
/// children as well as before the first child and after the last child. The
|
||||||
|
/// [spacing] is not applied before the first child or after the last child.
|
||||||
|
///
|
||||||
|
/// When the [spacing] is non-zero, the layout size will be larger than
|
||||||
|
/// the sum of the children's layout sizes in the main axis.
|
||||||
|
///
|
||||||
|
/// When the total children's layout sizes and total spacing between the
|
||||||
|
/// children is greater than the maximum constraints in the main axis, then
|
||||||
|
/// the children will overflow. For example, if there are two children and the
|
||||||
|
/// maximum constraint is 100.0 pixels, the children's layout sizes are 50.0
|
||||||
|
/// pixels each, and the spacing is 10.0 pixels, then the children will
|
||||||
|
/// overflow by 10.0 pixels.
|
||||||
|
///
|
||||||
|
/// Defaults to 0.0.
|
||||||
|
/// {@endtemplate}
|
||||||
|
double get spacing => _spacing;
|
||||||
|
double _spacing;
|
||||||
|
set spacing (double value) {
|
||||||
|
if (_spacing == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_spacing = value;
|
||||||
|
markNeedsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setupParentData(RenderBox child) {
|
void setupParentData(RenderBox child) {
|
||||||
if (child.parentData is! FlexParentData) {
|
if (child.parentData is! FlexParentData) {
|
||||||
@ -597,15 +663,15 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
|
|
||||||
double _getIntrinsicSize({
|
double _getIntrinsicSize({
|
||||||
required Axis sizingDirection,
|
required Axis sizingDirection,
|
||||||
required double extent, // the extent in the direction that isn't the sizing direction
|
required double extent, // The extent in the direction that isn't the sizing direction.
|
||||||
required _ChildSizingFunction childSize, // a method to find the size in the sizing direction
|
required _ChildSizingFunction childSize, // A method to find the size in the sizing direction.
|
||||||
}) {
|
}) {
|
||||||
if (_direction == sizingDirection) {
|
if (_direction == sizingDirection) {
|
||||||
// INTRINSIC MAIN SIZE
|
// INTRINSIC MAIN SIZE
|
||||||
// Intrinsic main size is the smallest size the flex container can take
|
// Intrinsic main size is the smallest size the flex container can take
|
||||||
// while maintaining the min/max-content contributions of its flex items.
|
// while maintaining the min/max-content contributions of its flex items.
|
||||||
double totalFlex = 0.0;
|
double totalFlex = 0.0;
|
||||||
double inflexibleSpace = 0.0;
|
double inflexibleSpace = spacing * (childCount - 1);
|
||||||
double maxFlexFractionSoFar = 0.0;
|
double maxFlexFractionSoFar = 0.0;
|
||||||
for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
|
for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
|
||||||
final int flex = _getFlex(child);
|
final int flex = _getFlex(child);
|
||||||
@ -825,7 +891,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
case Axis.vertical:
|
case Axis.vertical:
|
||||||
final double freeSpace = math.max(0.0, sizes.mainAxisFreeSpace);
|
final double freeSpace = math.max(0.0, sizes.mainAxisFreeSpace);
|
||||||
final bool flipMainAxis = _flipMainAxis;
|
final bool flipMainAxis = _flipMainAxis;
|
||||||
final (double leadingSpaceY, double spaceBetween) = mainAxisAlignment._distributeSpace(freeSpace, childCount, flipMainAxis);
|
final (double leadingSpaceY, double spaceBetween) = mainAxisAlignment._distributeSpace(freeSpace, childCount, flipMainAxis, spacing);
|
||||||
double y = flipMainAxis
|
double y = flipMainAxis
|
||||||
? leadingSpaceY + (childCount - 1) * spaceBetween + (sizes.axisSize.mainAxisExtent - sizes.mainAxisFreeSpace)
|
? leadingSpaceY + (childCount - 1) * spaceBetween + (sizes.axisSize.mainAxisExtent - sizes.mainAxisFreeSpace)
|
||||||
: leadingSpaceY;
|
: leadingSpaceY;
|
||||||
@ -978,7 +1044,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
int totalFlex = 0;
|
int totalFlex = 0;
|
||||||
RenderBox? firstFlexChild;
|
RenderBox? firstFlexChild;
|
||||||
_AscentDescent accumulatedAscentDescent = _AscentDescent.none;
|
_AscentDescent accumulatedAscentDescent = _AscentDescent.none;
|
||||||
_AxisSize accumulatedSize = _AxisSize.empty;
|
// Initially, accumulatedSize is the sum of the spaces between children in the main axis.
|
||||||
|
_AxisSize accumulatedSize = _AxisSize._(Size(spacing * (childCount - 1), 0.0));
|
||||||
for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
|
for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
|
||||||
final int flex;
|
final int flex;
|
||||||
if (canFlex && (flex = _getFlex(child)) > 0) {
|
if (canFlex && (flex = _getFlex(child)) > 0) {
|
||||||
@ -1064,7 +1131,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
final double remainingSpace = math.max(0.0, sizes.mainAxisFreeSpace);
|
final double remainingSpace = math.max(0.0, sizes.mainAxisFreeSpace);
|
||||||
final bool flipMainAxis = _flipMainAxis;
|
final bool flipMainAxis = _flipMainAxis;
|
||||||
final bool flipCrossAxis = _flipCrossAxis;
|
final bool flipCrossAxis = _flipCrossAxis;
|
||||||
final (double leadingSpace, double betweenSpace) = mainAxisAlignment._distributeSpace(remainingSpace, childCount, flipMainAxis);
|
final (double leadingSpace, double betweenSpace) = mainAxisAlignment._distributeSpace(remainingSpace, childCount, flipMainAxis, spacing);
|
||||||
final (_NextChild nextChild, RenderBox? topLeftChild) = flipMainAxis ? (childBefore, lastChild) : (childAfter, firstChild);
|
final (_NextChild nextChild, RenderBox? topLeftChild) = flipMainAxis ? (childBefore, lastChild) : (childAfter, firstChild);
|
||||||
final double? baselineOffset = sizes.baselineOffset;
|
final double? baselineOffset = sizes.baselineOffset;
|
||||||
assert(baselineOffset == null || (crossAxisAlignment == CrossAxisAlignment.baseline && direction == Axis.horizontal));
|
assert(baselineOffset == null || (crossAxisAlignment == CrossAxisAlignment.baseline && direction == Axis.horizontal));
|
||||||
@ -1192,5 +1259,6 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||||
properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: null));
|
properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: null));
|
||||||
properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
|
properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
|
||||||
|
properties.add(DoubleProperty('spacing', spacing, defaultValue: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4604,6 +4604,7 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
this.verticalDirection = VerticalDirection.down,
|
this.verticalDirection = VerticalDirection.down,
|
||||||
this.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
|
this.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
|
||||||
this.clipBehavior = Clip.none,
|
this.clipBehavior = Clip.none,
|
||||||
|
this.spacing = 0.0,
|
||||||
super.children,
|
super.children,
|
||||||
}) : assert(!identical(crossAxisAlignment, CrossAxisAlignment.baseline) || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline');
|
}) : assert(!identical(crossAxisAlignment, CrossAxisAlignment.baseline) || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline');
|
||||||
// Cannot use == in the assert above instead of identical because of https://github.com/dart-lang/language/issues/1811.
|
// Cannot use == in the assert above instead of identical because of https://github.com/dart-lang/language/issues/1811.
|
||||||
@ -4710,6 +4711,9 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
/// Defaults to [Clip.none].
|
/// Defaults to [Clip.none].
|
||||||
final Clip clipBehavior;
|
final Clip clipBehavior;
|
||||||
|
|
||||||
|
/// {@macro flutter.rendering.RenderFlex.spacing}
|
||||||
|
final double spacing;
|
||||||
|
|
||||||
bool get _needTextDirection {
|
bool get _needTextDirection {
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case Axis.horizontal:
|
case Axis.horizontal:
|
||||||
@ -4751,6 +4755,7 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
verticalDirection: verticalDirection,
|
verticalDirection: verticalDirection,
|
||||||
textBaseline: textBaseline,
|
textBaseline: textBaseline,
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
|
spacing: spacing,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4764,7 +4769,8 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
..textDirection = getEffectiveTextDirection(context)
|
..textDirection = getEffectiveTextDirection(context)
|
||||||
..verticalDirection = verticalDirection
|
..verticalDirection = verticalDirection
|
||||||
..textBaseline = textBaseline
|
..textBaseline = textBaseline
|
||||||
..clipBehavior = clipBehavior;
|
..clipBehavior = clipBehavior
|
||||||
|
..spacing = spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -4777,6 +4783,8 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||||
properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down));
|
properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down));
|
||||||
properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
|
properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
|
||||||
|
properties.add(EnumProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.none));
|
||||||
|
properties.add(DoubleProperty('spacing', spacing, defaultValue: 0.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4983,6 +4991,7 @@ class Row extends Flex {
|
|||||||
super.textDirection,
|
super.textDirection,
|
||||||
super.verticalDirection,
|
super.verticalDirection,
|
||||||
super.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
|
super.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
|
||||||
|
super.spacing,
|
||||||
super.children,
|
super.children,
|
||||||
}) : super(
|
}) : super(
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
@ -5174,6 +5183,7 @@ class Column extends Flex {
|
|||||||
super.textDirection,
|
super.textDirection,
|
||||||
super.verticalDirection,
|
super.verticalDirection,
|
||||||
super.textBaseline,
|
super.textBaseline,
|
||||||
|
super.spacing,
|
||||||
super.children,
|
super.children,
|
||||||
}) : super(
|
}) : super(
|
||||||
direction: Axis.vertical,
|
direction: Axis.vertical,
|
||||||
|
@ -109,6 +109,29 @@ void main() {
|
|||||||
expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0));
|
expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Vertical Overflow with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox flexible = RenderConstrainedBox(
|
||||||
|
additionalConstraints: const BoxConstraints.expand(),
|
||||||
|
);
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
spacing: 16.0,
|
||||||
|
children: <RenderBox>[
|
||||||
|
RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(height: 200.0)),
|
||||||
|
flexible,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final FlexParentData flexParentData = flexible.parentData! as FlexParentData;
|
||||||
|
flexParentData.flex = 1;
|
||||||
|
const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
|
||||||
|
layout(flex, constraints: viewport);
|
||||||
|
expect(flexible.size.height, equals(0.0));
|
||||||
|
expect(flex.getMinIntrinsicHeight(100.0), equals(216.0));
|
||||||
|
expect(flex.getMaxIntrinsicHeight(100.0), equals(216.0));
|
||||||
|
expect(flex.getMinIntrinsicWidth(100.0), equals(0.0));
|
||||||
|
expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0));
|
||||||
|
});
|
||||||
|
|
||||||
test('Horizontal Overflow', () {
|
test('Horizontal Overflow', () {
|
||||||
final RenderConstrainedBox flexible = RenderConstrainedBox(
|
final RenderConstrainedBox flexible = RenderConstrainedBox(
|
||||||
additionalConstraints: const BoxConstraints.expand(),
|
additionalConstraints: const BoxConstraints.expand(),
|
||||||
@ -131,6 +154,29 @@ void main() {
|
|||||||
expect(flex.getMaxIntrinsicWidth(100.0), equals(200.0));
|
expect(flex.getMaxIntrinsicWidth(100.0), equals(200.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Horizontal Overflow with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox flexible = RenderConstrainedBox(
|
||||||
|
additionalConstraints: const BoxConstraints.expand(),
|
||||||
|
);
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
spacing: 12.0,
|
||||||
|
children: <RenderBox>[
|
||||||
|
RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200.0)),
|
||||||
|
flexible,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final FlexParentData flexParentData = flexible.parentData! as FlexParentData;
|
||||||
|
flexParentData.flex = 1;
|
||||||
|
const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
|
||||||
|
layout(flex, constraints: viewport);
|
||||||
|
expect(flexible.size.width, equals(0.0));
|
||||||
|
expect(flex.getMinIntrinsicHeight(100.0), equals(0.0));
|
||||||
|
expect(flex.getMaxIntrinsicHeight(100.0), equals(0.0));
|
||||||
|
expect(flex.getMinIntrinsicWidth(100.0), equals(212.0));
|
||||||
|
expect(flex.getMaxIntrinsicWidth(100.0), equals(212.0));
|
||||||
|
});
|
||||||
|
|
||||||
test('Vertical Flipped Constraints', () {
|
test('Vertical Flipped Constraints', () {
|
||||||
final RenderFlex flex = RenderFlex(
|
final RenderFlex flex = RenderFlex(
|
||||||
direction: Axis.vertical,
|
direction: Axis.vertical,
|
||||||
@ -162,7 +208,8 @@ void main() {
|
|||||||
' mainAxisAlignment: start\n'
|
' mainAxisAlignment: start\n'
|
||||||
' mainAxisSize: max\n'
|
' mainAxisSize: max\n'
|
||||||
' crossAxisAlignment: center\n'
|
' crossAxisAlignment: center\n'
|
||||||
' verticalDirection: down\n',
|
' verticalDirection: down\n'
|
||||||
|
' spacing: 0.0\n',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -253,6 +300,215 @@ void main() {
|
|||||||
expect(box3.size.height, equals(100.0));
|
expect(box3.size.height, equals(100.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.start with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, equals(0.0));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(114.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, equals(228.0));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(0.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(114.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(228.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.end with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, equals(172.0));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(286.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, equals(400.0));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(72.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(186.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(300.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.center with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, equals(86.0));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(200.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, equals(314.0));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(36.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(150.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(264.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.spaceEvenly with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, equals(43.0));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(200.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, equals(357.0));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(18.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(150.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(282.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.spaceAround with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, closeTo(28.6, 0.1));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(200.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, closeTo(371.3, 0.1));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(12.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(150.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(288.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MainAxisAlignment.spaceBetween with RenderFlex.spacing', () {
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
spacing: 14.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
layout(flex, constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500.0,
|
||||||
|
maxHeight: 400.0,
|
||||||
|
));
|
||||||
|
Offset getOffset(RenderBox box) {
|
||||||
|
final FlexParentData parentData = box.parentData! as FlexParentData;
|
||||||
|
return parentData.offset;
|
||||||
|
}
|
||||||
|
expect(getOffset(box1).dx, equals(0.0));
|
||||||
|
expect(box1.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box2).dx, equals(200.0));
|
||||||
|
expect(box2.size.width, equals(100.0));
|
||||||
|
expect(getOffset(box3).dx, equals(400.0));
|
||||||
|
expect(box3.size.width, equals(100.0));
|
||||||
|
|
||||||
|
flex.direction = Axis.vertical;
|
||||||
|
pumpFrame();
|
||||||
|
expect(getOffset(box1).dy, equals(0.0));
|
||||||
|
expect(box1.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box2).dy, equals(150.0));
|
||||||
|
expect(box2.size.height, equals(100.0));
|
||||||
|
expect(getOffset(box3).dy, equals(300.0));
|
||||||
|
expect(box3.size.height, equals(100.0));
|
||||||
|
});
|
||||||
|
|
||||||
test('Fit.loose', () {
|
test('Fit.loose', () {
|
||||||
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
|
||||||
@ -719,6 +975,61 @@ void main() {
|
|||||||
expect(flex.getMaxIntrinsicWidth(500.0), 200.0 + 500.0);
|
expect(flex.getMaxIntrinsicWidth(500.0), 200.0 + 500.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('main/cross axis intrinsics in horizontal direction and RenderFlex.spacing', () {
|
||||||
|
const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
spacing: 16.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(double.infinity), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(double.infinity), 332.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(double.infinity), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(double.infinity), 100.0);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(300.0), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(300.0), 332.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(300.0), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(300.0), 100.0);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(500.0), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(500.0), 332.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(500.0), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(500.0), 100.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('main/cross axis intrinsics in vertical direction and RenderFlex.spacing', () {
|
||||||
|
const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
|
||||||
|
final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
|
||||||
|
final RenderFlex flex = RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
direction: Axis.vertical,
|
||||||
|
spacing: 16.0,
|
||||||
|
);
|
||||||
|
flex.addAll(<RenderBox>[box1, box2, box3]);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(double.infinity), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(double.infinity), 100.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(double.infinity), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(double.infinity), 332.0);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(300.0), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(300.0), 100.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(300.0), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(300.0), 332.0);
|
||||||
|
|
||||||
|
expect(flex.getMinIntrinsicWidth(500.0), 100.0);
|
||||||
|
expect(flex.getMaxIntrinsicWidth(500.0), 100.0);
|
||||||
|
expect(flex.getMinIntrinsicHeight(500.0), 332.0);
|
||||||
|
expect(flex.getMaxIntrinsicHeight(500.0), 332.0);
|
||||||
|
});
|
||||||
|
|
||||||
test('cross axis intrinsics, with ascending flex flow layout', () {
|
test('cross axis intrinsics, with ascending flex flow layout', () {
|
||||||
const BoxConstraints square = BoxConstraints.tightFor(width: 5.0, height: 5.0);
|
const BoxConstraints square = BoxConstraints.tightFor(width: 5.0, height: 5.0);
|
||||||
// 3 'A's separated by zero-width spaces. Max intrinsic width = 30, min intrinsic width = 10
|
// 3 'A's separated by zero-width spaces. Max intrinsic width = 30, min intrinsic width = 10
|
||||||
@ -909,6 +1220,21 @@ void main() {
|
|||||||
// ignore: avoid_dynamic_calls
|
// ignore: avoid_dynamic_calls
|
||||||
expect(exceptions.first.message, isNot(contains('Null check operator')));
|
expect(exceptions.first.message, isNot(contains('Null check operator')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Negative RenderFlex.spacing throws an exception', () {
|
||||||
|
final List<dynamic> exceptions = <dynamic>[];
|
||||||
|
final RenderDecoratedBox box = RenderDecoratedBox(decoration: const BoxDecoration());
|
||||||
|
try {
|
||||||
|
RenderFlex(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
spacing: -15.0,
|
||||||
|
children: <RenderBox>[box],
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
expect(exceptions, hasLength(1));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class RenderFlowBaselineTestBox extends RenderBox {
|
class RenderFlowBaselineTestBox extends RenderBox {
|
||||||
|
@ -7,6 +7,41 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
Widget constrainedFlex({
|
||||||
|
required Axis direction,
|
||||||
|
required MainAxisAlignment mainAxisAlignment,
|
||||||
|
required double spacing,
|
||||||
|
}) {
|
||||||
|
return Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 300.0,
|
||||||
|
height: 300.0,
|
||||||
|
child: Flex(
|
||||||
|
direction: direction,
|
||||||
|
mainAxisAlignment: mainAxisAlignment,
|
||||||
|
spacing: spacing,
|
||||||
|
children: const <Widget>[
|
||||||
|
SizedBox(
|
||||||
|
width: 50.0,
|
||||||
|
height: 50.0,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 50.0,
|
||||||
|
height: 50.0,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 50.0,
|
||||||
|
height: 50.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
testWidgets('Can hit test flex children of stacks', (WidgetTester tester) async {
|
testWidgets('Can hit test flex children of stacks', (WidgetTester tester) async {
|
||||||
bool didReceiveTap = false;
|
bool didReceiveTap = false;
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@ -147,4 +182,164 @@ void main() {
|
|||||||
const Column();
|
const Column();
|
||||||
const Row();
|
const Row();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Default Flex.spacing value', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(const Flex(direction: Axis.vertical));
|
||||||
|
|
||||||
|
final Flex flex = tester.widget(find.byType(Flex));
|
||||||
|
expect(flex.spacing, 0.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Can update Flex.spacing value', (WidgetTester tester) async {
|
||||||
|
Widget buildFlex({ required double spacing }) {
|
||||||
|
return Center(
|
||||||
|
child: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Flex(
|
||||||
|
spacing: spacing,
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
height: 100.0,
|
||||||
|
width: 100.0,
|
||||||
|
color: const Color(0xFFFF0000),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 100.0,
|
||||||
|
width: 100.0,
|
||||||
|
color: const Color(0xFF0000FF),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 100.0,
|
||||||
|
width: 100.0,
|
||||||
|
color: const Color(0xff00FF00),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildFlex(spacing: 8.0));
|
||||||
|
|
||||||
|
RenderFlex renderObject = tester.allRenderObjects.whereType<RenderFlex>().first;
|
||||||
|
expect(renderObject.spacing, equals(8.0));
|
||||||
|
expect(tester.getSize(find.byType(Flex)).width, equals(100.0));
|
||||||
|
expect(tester.getSize(find.byType(Flex)).height, equals(316.0));
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildFlex(spacing: 18.0));
|
||||||
|
|
||||||
|
renderObject = tester.allRenderObjects.whereType<RenderFlex>().first;
|
||||||
|
expect(renderObject.spacing, equals(18.0));
|
||||||
|
expect(tester.getSize(find.byType(Flex)).width, equals(100.0));
|
||||||
|
expect(tester.getSize(find.byType(Flex)).height, equals(336.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.start and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.end and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.center and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.spaceAround and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.spaceEvenly and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Overconstrained Flex with MainAxisAlignment.spaceBetween and spacing', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
spacing: 50.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 50.0 * 2 (spacing) = 250.0 < 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(constrainedFlex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
spacing: 100.0,
|
||||||
|
));
|
||||||
|
// 50.0 * 3 (children) + 100.0 * 2 (spacing) = 350.0 > 300.0 (constraints)
|
||||||
|
expect(tester.takeException(), isAssertionError);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -278,6 +278,7 @@ void main() {
|
|||||||
' crossAxisAlignment: center',
|
' crossAxisAlignment: center',
|
||||||
' textDirection: ltr',
|
' textDirection: ltr',
|
||||||
' verticalDirection: down',
|
' verticalDirection: down',
|
||||||
|
' spacing: 0.0',
|
||||||
'◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤',
|
'◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤',
|
||||||
'════════════════════════════════════════════════════════════════════════════════════════════════════',
|
'════════════════════════════════════════════════════════════════════════════════════════════════════',
|
||||||
'',
|
'',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user