Fix bugs in RenderSizedOverflowBox and RenderFractionallySizedOverflowBox (#23492)
Bug #1: These didn't work with directional alignments, due to an error in the types of the constructor arguments. Bug #2: Pretty sure RenderSizedOverflowBox never worked at all. As soon as I wrote a test for it, the test showed that there was a fundamental bug in its performLayout method: it didn't set parentUsesSize, but it immediately tried to use the child's size.
This commit is contained in:
parent
48a5804dd8
commit
53308465c7
@ -229,6 +229,9 @@ abstract class RenderAligningShiftedBox extends RenderShiftedBox {
|
|||||||
/// Initializes member variables for subclasses.
|
/// Initializes member variables for subclasses.
|
||||||
///
|
///
|
||||||
/// The [alignment] argument must not be null.
|
/// The [alignment] argument must not be null.
|
||||||
|
///
|
||||||
|
/// The [textDirection] must be non-null if the [alignment] is
|
||||||
|
/// direction-sensitive.
|
||||||
RenderAligningShiftedBox({
|
RenderAligningShiftedBox({
|
||||||
AlignmentGeometry alignment = Alignment.center,
|
AlignmentGeometry alignment = Alignment.center,
|
||||||
@required TextDirection textDirection,
|
@required TextDirection textDirection,
|
||||||
@ -303,6 +306,7 @@ abstract class RenderAligningShiftedBox extends RenderShiftedBox {
|
|||||||
///
|
///
|
||||||
/// This method must be called after the child has been laid out and
|
/// This method must be called after the child has been laid out and
|
||||||
/// this object's own size has been set.
|
/// this object's own size has been set.
|
||||||
|
@protected
|
||||||
void alignChild() {
|
void alignChild() {
|
||||||
_resolve();
|
_resolve();
|
||||||
assert(child != null);
|
assert(child != null);
|
||||||
@ -707,6 +711,9 @@ class RenderUnconstrainedBox extends RenderAligningShiftedBox with DebugOverflow
|
|||||||
/// A render object that is a specific size but passes its original constraints
|
/// A render object that is a specific size but passes its original constraints
|
||||||
/// through to its child, which it allows to overflow.
|
/// through to its child, which it allows to overflow.
|
||||||
///
|
///
|
||||||
|
/// If the child's resulting size differs from this render object's size, then
|
||||||
|
/// the child is aligned according to the [alignment] property.
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
/// * [RenderUnconstrainedBox] for a render object that allows its children
|
/// * [RenderUnconstrainedBox] for a render object that allows its children
|
||||||
/// to render themselves unconstrained, expands to fit them, and considers
|
/// to render themselves unconstrained, expands to fit them, and considers
|
||||||
@ -717,11 +724,14 @@ class RenderUnconstrainedBox extends RenderAligningShiftedBox with DebugOverflow
|
|||||||
class RenderSizedOverflowBox extends RenderAligningShiftedBox {
|
class RenderSizedOverflowBox extends RenderAligningShiftedBox {
|
||||||
/// Creates a render box of a given size that lets its child overflow.
|
/// Creates a render box of a given size that lets its child overflow.
|
||||||
///
|
///
|
||||||
/// The [requestedSize] argument must not be null.
|
/// The [requestedSize] and [alignment] arguments must not be null.
|
||||||
|
///
|
||||||
|
/// The [textDirection] argument must not be null if the [alignment] is
|
||||||
|
/// direction-sensitive.
|
||||||
RenderSizedOverflowBox({
|
RenderSizedOverflowBox({
|
||||||
RenderBox child,
|
RenderBox child,
|
||||||
@required Size requestedSize,
|
@required Size requestedSize,
|
||||||
Alignment alignment = Alignment.center,
|
AlignmentGeometry alignment = Alignment.center,
|
||||||
TextDirection textDirection,
|
TextDirection textDirection,
|
||||||
}) : assert(requestedSize != null),
|
}) : assert(requestedSize != null),
|
||||||
_requestedSize = requestedSize,
|
_requestedSize = requestedSize,
|
||||||
@ -769,7 +779,7 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox {
|
|||||||
void performLayout() {
|
void performLayout() {
|
||||||
size = constraints.constrain(_requestedSize);
|
size = constraints.constrain(_requestedSize);
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
child.layout(constraints);
|
child.layout(constraints, parentUsesSize: true);
|
||||||
alignChild();
|
alignChild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -783,17 +793,24 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox {
|
|||||||
/// for a given axis is null, then the constraints from the parent are just
|
/// for a given axis is null, then the constraints from the parent are just
|
||||||
/// passed through instead.
|
/// passed through instead.
|
||||||
///
|
///
|
||||||
/// It then tries to size itself to the size of its child.
|
/// It then tries to size itself to the size of its child. Where this is not
|
||||||
|
/// possible (e.g. if the constraints from the parent are themselves tight), the
|
||||||
|
/// child is aligned according to [alignment].
|
||||||
class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox {
|
class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox {
|
||||||
/// Creates a render box that sizes its child to a fraction of the total available space.
|
/// Creates a render box that sizes its child to a fraction of the total available space.
|
||||||
///
|
///
|
||||||
/// If non-null, the [widthFactor] and [heightFactor] arguments must be
|
/// If non-null, the [widthFactor] and [heightFactor] arguments must be
|
||||||
/// non-negative.
|
/// non-negative.
|
||||||
|
///
|
||||||
|
/// The [alignment] must not be null.
|
||||||
|
///
|
||||||
|
/// The [textDirection] must be non-null if the [alignment] is
|
||||||
|
/// direction-sensitive.
|
||||||
RenderFractionallySizedOverflowBox({
|
RenderFractionallySizedOverflowBox({
|
||||||
RenderBox child,
|
RenderBox child,
|
||||||
double widthFactor,
|
double widthFactor,
|
||||||
double heightFactor,
|
double heightFactor,
|
||||||
Alignment alignment = Alignment.center,
|
AlignmentGeometry alignment = Alignment.center,
|
||||||
TextDirection textDirection,
|
TextDirection textDirection,
|
||||||
}) : _widthFactor = widthFactor,
|
}) : _widthFactor = widthFactor,
|
||||||
_heightFactor = heightFactor,
|
_heightFactor = heightFactor,
|
||||||
|
@ -29,4 +29,36 @@ void main() {
|
|||||||
expect(box.size, equals(const Size(50.0, 25.0)));
|
expect(box.size, equals(const Size(50.0, 25.0)));
|
||||||
expect(box.localToGlobal(Offset.zero), equals(const Offset(25.0, 37.5)));
|
expect(box.localToGlobal(Offset.zero), equals(const Offset(25.0, 37.5)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('FractionallySizedBox alignment', (WidgetTester tester) async {
|
||||||
|
final GlobalKey inner = GlobalKey();
|
||||||
|
await tester.pumpWidget(Directionality(
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
child: FractionallySizedBox(
|
||||||
|
widthFactor: 0.5,
|
||||||
|
heightFactor: 0.5,
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
child: Placeholder(key: inner),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
final RenderBox box = inner.currentContext.findRenderObject();
|
||||||
|
expect(box.size, equals(const Size(400.0, 300.0)));
|
||||||
|
expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(800.0 - 400.0 / 2.0, 0.0 + 300.0 / 2.0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('FractionallySizedBox alignment (direction-sensitive)', (WidgetTester tester) async {
|
||||||
|
final GlobalKey inner = GlobalKey();
|
||||||
|
await tester.pumpWidget(Directionality(
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
child: FractionallySizedBox(
|
||||||
|
widthFactor: 0.5,
|
||||||
|
heightFactor: 0.5,
|
||||||
|
alignment: AlignmentDirectional.topEnd,
|
||||||
|
child: Placeholder(key: inner),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
final RenderBox box = inner.currentContext.findRenderObject();
|
||||||
|
expect(box.size, equals(const Size(400.0, 300.0)));
|
||||||
|
expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(0.0 + 400.0 / 2.0, 0.0 + 300.0 / 2.0)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -49,4 +49,50 @@ void main() {
|
|||||||
'maxHeight: 4.0',
|
'maxHeight: 4.0',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('SizedOverflowBox alignment', (WidgetTester tester) async {
|
||||||
|
final GlobalKey inner = GlobalKey();
|
||||||
|
await tester.pumpWidget(Directionality(
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
child: Center(
|
||||||
|
child: SizedOverflowBox(
|
||||||
|
size: const Size(100.0, 100.0),
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
child: Container(height: 50.0, width: 50.0, key: inner),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
final RenderBox box = inner.currentContext.findRenderObject();
|
||||||
|
expect(box.size, equals(const Size(50.0, 50.0)));
|
||||||
|
expect(
|
||||||
|
box.localToGlobal(box.size.center(Offset.zero)),
|
||||||
|
equals(const Offset(
|
||||||
|
(800.0 - 100.0) / 2.0 + 100.0 - 50.0 / 2.0,
|
||||||
|
(600.0 - 100.0) / 2.0 + 0.0 + 50.0 / 2.0,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('SizedOverflowBox alignment (direction-sensitive)', (WidgetTester tester) async {
|
||||||
|
final GlobalKey inner = GlobalKey();
|
||||||
|
await tester.pumpWidget(Directionality(
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
child: Center(
|
||||||
|
child: SizedOverflowBox(
|
||||||
|
size: const Size(100.0, 100.0),
|
||||||
|
alignment: AlignmentDirectional.bottomStart,
|
||||||
|
child: Container(height: 50.0, width: 50.0, key: inner),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
final RenderBox box = inner.currentContext.findRenderObject();
|
||||||
|
expect(box.size, equals(const Size(50.0, 50.0)));
|
||||||
|
expect(
|
||||||
|
box.localToGlobal(box.size.center(Offset.zero)),
|
||||||
|
equals(const Offset(
|
||||||
|
(800.0 - 100.0) / 2.0 + 100.0 - 50.0 / 2.0,
|
||||||
|
(600.0 - 100.0) / 2.0 + 100.0 - 50.0 / 2.0,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user