Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
8c44abc0
Unverified
Commit
8c44abc0
authored
Mar 19, 2021
by
LongCatIsLooong
Committed by
GitHub
Mar 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ConstraintsTransformBox (#77994)
parent
74a795d1
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
473 additions
and
88 deletions
+473
-88
debug_overflow_indicator.dart
...s/flutter/lib/src/rendering/debug_overflow_indicator.dart
+2
-1
shifted_box.dart
packages/flutter/lib/src/rendering/shifted_box.dart
+160
-69
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+247
-16
box_test.dart
packages/flutter/test/rendering/box_test.dart
+42
-0
debug_overflow_indicator_test.dart
...flutter/test/rendering/debug_overflow_indicator_test.dart
+1
-1
basic_test.dart
packages/flutter/test/widgets/basic_test.dart
+21
-1
No files found.
packages/flutter/lib/src/rendering/debug_overflow_indicator.dart
View file @
8c44abc0
...
...
@@ -85,7 +85,8 @@ class _OverflowRegionData {
///
/// See also:
///
/// * [RenderUnconstrainedBox] and [RenderFlex] for examples of classes that use this indicator mixin.
/// * [RenderConstraintsTransformBox], [RenderUnconstrainedBox] and
/// [RenderFlex], for examples of classes that use this indicator mixin.
mixin
DebugOverflowIndicatorMixin
on
RenderObject
{
static
const
Color
_black
=
Color
(
0xBF000000
);
static
const
Color
_yellow
=
Color
(
0xBFFFFF00
);
...
...
packages/flutter/lib/src/rendering/shifted_box.dart
View file @
8c44abc0
...
...
@@ -10,10 +10,17 @@ import 'box.dart';
import
'debug.dart'
;
import
'debug_overflow_indicator.dart'
;
import
'layer.dart'
;
import
'layout_helper.dart'
;
import
'object.dart'
;
import
'stack.dart'
show
RelativeRect
;
/// Signature for a function that transforms a [BoxConstraints] to another
/// [BoxConstraints].
///
/// Used by [RenderConstraintsTransformBox] and [ConstraintsTransformBox].
/// Typically the caller requires the returned [BoxConstraints] to be
/// [BoxConstraints.isNormalized].
typedef
BoxConstraintsTransform
=
BoxConstraints
Function
(
BoxConstraints
);
/// Abstract class for one-child-layout render boxes that provide control over
/// the child's position.
abstract
class
RenderShiftedBox
extends
RenderBox
with
RenderObjectWithChildMixin
<
RenderBox
>
{
...
...
@@ -628,71 +635,83 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox {
}
}
/// Renders a box, imposing no constraints on its child, allowing the child to
/// render at its "natural" size.
/// A [RenderBox] that applies an arbitrary transform to its [constraints]
/// before sizing its child using the new constraints, treating any overflow as
/// error.
///
/// This allows a child to render at the size it would render if it were alone
/// on an infinite canvas with no constraints. This box will then attempt to
/// adopt the same size, within the limits of its own constraints. If it ends
/// up with a different size, it will align the child based on [alignment].
/// If the box cannot expand enough to accommodate the entire child, the
/// child will be clipped.
/// This [RenderBox] sizes its child using a [BoxConstraints] created by
/// applying [constraintsTransform] to this [RenderBox]'s own [constraints].
/// This box will then attempt to adopt the same size, within the limits of its
/// own constraints. If it ends up with a different size, it will align the
/// child based on [alignment]. If the box cannot expand enough to accommodate
/// the entire child, the child will be clipped if [clipBehavior] is not
/// [Clip.none].
///
/// In debug mode, if the child overflows the box, a warning will be printed on
/// the console, and black and yellow striped areas will appear where the
/// overflow occurs.
///
/// When [child] is null, this [RenderBox] takes the smallest possible size and
/// never overflows.
///
/// This [RenderBox] can be used to ensure some of [child]'s natrual dimensions
/// are honored, and get an early warning during development otherwise. For
/// instance, if [child] requires a minimum height to fully display its content,
/// [constraintsTransform] can be set to a function that removes the `maxHeight`
/// constraint from the incoming [BoxConstraints], so that if the parent
/// [RenderObject] fails to provide enough vertical space, a warning will be
/// displayed in debug mode, while still allowing [child] to grow vertically.
///
/// See also:
///
/// * [ConstraintsTransformBox], the widget that makes use of this
/// [RenderObject] and exposes the same functionality.
/// * [RenderConstrainedBox], which renders a box which imposes constraints
/// on its child.
/// * [RenderConstrainedOverflowBox], which renders a box that imposes different
/// constraints on its child than it gets from its parent, possibly allowing
/// the child to overflow the parent.
/// * [RenderSizedOverflowBox], a render object that is a specific size but
/// passes its original constraints through to its child, which it allows to
/// overflow.
class
RenderUnconstrainedBox
extends
RenderAligningShiftedBox
with
DebugOverflowIndicatorMixin
{
/// Create a render object that sizes itself to the child but does not
/// pass the [constraints] down to that child.
/// * [RenderUnconstrainedBox] which allows its children to render themselves
/// unconstrained, expands to fit them, and considers overflow to be an error.
class
RenderConstraintsTransformBox
extends
RenderAligningShiftedBox
with
DebugOverflowIndicatorMixin
{
/// Creates a [RenderBox] that sizes itself to the child and modifies the
/// [constraints] before passing it down to that child.
///
/// The [alignment] must not be null.
Render
Unconstrained
Box
({
/// The [alignment]
and [clipBehavior]
must not be null.
Render
ConstraintsTransform
Box
({
required
AlignmentGeometry
alignment
,
required
TextDirection
?
textDirection
,
Axis
?
constrainedAxis
,
required
BoxConstraintsTransform
constraintsTransform
,
RenderBox
?
child
,
Clip
clipBehavior
=
Clip
.
none
,
})
:
assert
(
alignment
!=
null
),
assert
(
clipBehavior
!=
null
),
_constrainedAxis
=
constrainedAxis
,
assert
(
constraintsTransform
!=
null
),
_constraintsTransform
=
constraintsTransform
,
_clipBehavior
=
clipBehavior
,
super
.
mixin
(
alignment
,
textDirection
,
child
);
/// The axis to retain constraints on, if any.
///
/// If not set, or set to null (the default), neither axis will retain its
/// constraints. If set to [Axis.vertical], then vertical constraints will
/// be retained, and if set to [Axis.horizontal], then horizontal constraints
/// will be retained.
Axis
?
get
constrainedAxis
=>
_constrainedAxis
;
Axis
?
_constrainedAxis
;
set
constrainedAxis
(
Axis
?
value
)
{
if
(
_constrainedAxis
==
value
)
/// {@macro flutter.widgets.constraintsTransform}
BoxConstraintsTransform
get
constraintsTransform
=>
_constraintsTransform
;
BoxConstraintsTransform
_constraintsTransform
;
set
constraintsTransform
(
BoxConstraintsTransform
value
)
{
if
(
_constraintsTransform
==
value
)
return
;
_constrainedAxis
=
value
;
_constraintsTransform
=
value
;
// The RenderObject only needs layout if the new transform maps the current
// `constraints` to a different value, or the render object has never been
// laid out before.
final
bool
needsLayout
=
_childConstraints
==
null
||
_childConstraints
!=
value
(
constraints
);
if
(
needsLayout
)
markNeedsLayout
();
}
Rect
_overflowContainerRect
=
Rect
.
zero
;
Rect
_overflowChildRect
=
Rect
.
zero
;
bool
_isOverflowing
=
false
;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.none], and must not be null.
Clip
get
clipBehavior
=>
_clipBehavior
;
Clip
_clipBehavior
=
Clip
.
none
;
Clip
_clipBehavior
;
set
clipBehavior
(
Clip
value
)
{
assert
(
value
!=
null
);
if
(
value
!=
_clipBehavior
)
{
...
...
@@ -702,49 +721,33 @@ class RenderUnconstrainedBox extends RenderAligningShiftedBox with DebugOverflow
}
}
Size
_calculateSizeWithChild
({
required
BoxConstraints
constraints
,
required
ChildLayouter
layoutChild
})
{
assert
(
child
!=
null
);
// Let the child lay itself out at it's "natural" size, but if
// constrainedAxis is non-null, keep any constraints on that axis.
final
BoxConstraints
childConstraints
;
if
(
constrainedAxis
!=
null
)
{
switch
(
constrainedAxis
!)
{
case
Axis
.
horizontal
:
childConstraints
=
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
,
minWidth:
constraints
.
minWidth
);
break
;
case
Axis
.
vertical
:
childConstraints
=
BoxConstraints
(
maxHeight:
constraints
.
maxHeight
,
minHeight:
constraints
.
minHeight
);
break
;
}
}
else
{
childConstraints
=
const
BoxConstraints
();
}
return
constraints
.
constrain
(
layoutChild
(
child
!,
childConstraints
));
}
@override
Size
computeDryLayout
(
BoxConstraints
constraints
)
{
if
(
child
==
null
)
{
return
constraints
.
smallest
;
}
return
_calculateSizeWithChild
(
constraints:
constraints
,
layoutChild:
ChildLayoutHelper
.
dryLayoutChild
,
);
final
Size
?
childSize
=
child
?.
getDryLayout
(
constraintsTransform
(
constraints
));
return
childSize
==
null
?
constraints
.
smallest
:
constraints
.
constrain
(
childSize
);
}
Rect
_overflowContainerRect
=
Rect
.
zero
;
Rect
_overflowChildRect
=
Rect
.
zero
;
bool
_isOverflowing
=
false
;
BoxConstraints
?
_childConstraints
;
@override
void
performLayout
()
{
final
BoxConstraints
constraints
=
this
.
constraints
;
final
RenderBox
?
child
=
this
.
child
;
if
(
child
!=
null
)
{
size
=
_calculateSizeWithChild
(
constraints:
constraints
,
layoutChild:
ChildLayoutHelper
.
layoutChild
,
);
final
BoxConstraints
childConstraints
=
constraintsTransform
(
constraints
);
assert
(
childConstraints
!=
null
);
assert
(
childConstraints
.
isNormalized
,
'
$childConstraints
is not normalized'
);
_childConstraints
=
childConstraints
;
child
.
layout
(
childConstraints
,
parentUsesSize:
true
);
size
=
constraints
.
constrain
(
child
.
size
);
alignChild
();
final
BoxParentData
childParentData
=
child
!
.
parentData
!
as
BoxParentData
;
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
_overflowContainerRect
=
Offset
.
zero
&
size
;
_overflowChildRect
=
childParentData
.
offset
&
child
!
.
size
;
_overflowChildRect
=
childParentData
.
offset
&
child
.
size
;
}
else
{
size
=
constraints
.
smallest
;
_overflowContainerRect
=
Rect
.
zero
;
...
...
@@ -797,6 +800,94 @@ class RenderUnconstrainedBox extends RenderAligningShiftedBox with DebugOverflow
}
}
/// Renders a box, imposing no constraints on its child, allowing the child to
/// render at its "natural" size.
///
/// The class is deprecated, use [RenderConstraintsTransformBox] instead.
///
/// This allows a child to render at the size it would render if it were alone
/// on an infinite canvas with no constraints. This box will then attempt to
/// adopt the same size, within the limits of its own constraints. If it ends
/// up with a different size, it will align the child based on [alignment].
/// If the box cannot expand enough to accommodate the entire child, the
/// child will be clipped.
///
/// In debug mode, if the child overflows the box, a warning will be printed on
/// the console, and black and yellow striped areas will appear where the
/// overflow occurs.
///
/// See also:
///
/// * [RenderConstrainedBox], which renders a box which imposes constraints
/// on its child.
/// * [RenderConstrainedOverflowBox], which renders a box that imposes different
/// constraints on its child than it gets from its parent, possibly allowing
/// the child to overflow the parent.
/// * [RenderSizedOverflowBox], a render object that is a specific size but
/// passes its original constraints through to its child, which it allows to
/// overflow.
///
@Deprecated
(
'Use RenderConstraintsTransformBox instead. '
'This feature was deprecated after v2.1.0-11.0.pre.'
)
class
RenderUnconstrainedBox
extends
RenderConstraintsTransformBox
{
/// Create a render object that sizes itself to the child but does not
/// pass the [constraints] down to that child.
///
/// The [alignment] and [clipBehavior] must not be null.
@Deprecated
(
'Use RenderConstraintsTransformBox instead. '
'This feature was deprecated after v2.1.0-11.0.pre.'
)
RenderUnconstrainedBox
({
required
AlignmentGeometry
alignment
,
required
TextDirection
?
textDirection
,
Axis
?
constrainedAxis
,
RenderBox
?
child
,
Clip
clipBehavior
=
Clip
.
none
,
})
:
assert
(
alignment
!=
null
),
assert
(
clipBehavior
!=
null
),
_constrainedAxis
=
constrainedAxis
,
super
(
alignment:
alignment
,
textDirection:
textDirection
,
child:
child
,
clipBehavior:
clipBehavior
,
constraintsTransform:
_convertAxis
(
constrainedAxis
),
);
/// The axis to retain constraints on, if any.
///
/// If not set, or set to null (the default), neither axis will retain its
/// constraints. If set to [Axis.vertical], then vertical constraints will
/// be retained, and if set to [Axis.horizontal], then horizontal constraints
/// will be retained.
Axis
?
get
constrainedAxis
=>
_constrainedAxis
;
Axis
?
_constrainedAxis
;
set
constrainedAxis
(
Axis
?
value
)
{
if
(
_constrainedAxis
==
value
)
return
;
_constrainedAxis
=
value
;
constraintsTransform
=
_convertAxis
(
constrainedAxis
);
}
static
BoxConstraints
_unconstrained
(
BoxConstraints
constraints
)
=>
const
BoxConstraints
();
static
BoxConstraints
_widthConstrained
(
BoxConstraints
constraints
)
=>
constraints
.
widthConstraints
();
static
BoxConstraints
_heightConstrained
(
BoxConstraints
constraints
)
=>
constraints
.
heightConstraints
();
static
BoxConstraintsTransform
_convertAxis
(
Axis
?
constrainedAxis
)
{
if
(
constrainedAxis
==
null
)
{
return
_unconstrained
;
}
switch
(
constrainedAxis
)
{
case
Axis
.
horizontal
:
return
_widthConstrained
;
case
Axis
.
vertical
:
return
_heightConstrained
;
}
}
}
/// A render object that is a specific size but passes its original constraints
/// through to its child, which it allows to overflow.
///
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
8c44abc0
...
...
@@ -28,6 +28,7 @@ export 'package:flutter/rendering.dart' show
AlignmentGeometryTween
,
Axis
,
BoxConstraints
,
BoxConstraintsTransform
,
CrossAxisAlignment
,
CustomClipper
,
CustomPainter
,
...
...
@@ -2317,6 +2318,221 @@ class ConstrainedBox extends SingleChildRenderObjectWidget {
}
}
/// A container widget that applies an arbitrary transform to its constraints,
/// and sizes its child using the resulting [BoxConstraints], treating any
/// overflow as error.
///
/// This container sizes its child using a [BoxConstraints] created by applying
/// [constraintsTransform] to its own constraints. This container will then
/// attempt to adopt the same size, within the limits of its own constraints. If
/// it ends up with a different size, it will align the child based on
/// [alignment]. If the container cannot expand enough to accommodate the entire
/// child, the child will be clipped if [clipBehavior] is not [Clip.none].
///
/// In debug mode, if the child overflows the container, a warning will be
/// printed on the console, and black and yellow striped areas will appear where
/// the overflow occurs.
///
/// When [child] is null, this widget becomes as small as possible and never
/// overflows
///
/// This widget can be used to ensure some of [child]'s natrual dimensions are
/// honored, and get an early warning otherwise during development. For
/// instance, if [child] requires a minimum height to fully display its content,
/// [constraintsTransform] can be set to [maxHeightUnconstrained], so that if
/// the parent [RenderObject] fails to provide enough vertical space, a warning
/// will be displayed in debug mode, while still allowing [child] to grow
/// vertically:
///
/// {@tool snippet}
/// In the following snippet, the [Card] is guaranteed to be at least as tall as
/// its "natrual" height. Unlike [UnconstrainedBox], it will become taller if
/// its "natrual" height is smaller than 40 px. If the [Container] isn't high
/// enough to show the full content of the [Card], in debug mode a warning will
/// be given.
///
/// ```dart
/// Container(
/// constraints: BoxConstraints(minHeight: 40, maxHeight: 100),
/// alignment: Alignment.center,
/// child: ConstraintsTransformBox(
/// constraintsTransform: ConstraintsTransformBox.maxHeightUnconstrained,
/// child: const Card(child: Text('Hello World!')),
/// )
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [ConstrainedBox], which renders a box which imposes constraints
/// on its child.
/// * [OverflowBox], a widget that imposes additional constraints on its child,
/// and allows the child to overflow itself.
/// * [UnconstrainedBox] which allows its children to render themselves
/// unconstrained, expands to fit them, and considers overflow to be an error.
class
ConstraintsTransformBox
extends
SingleChildRenderObjectWidget
{
/// Creates a widget that uses a function to transform the constraints it
/// passes to its child. If the child overflows the parent's constraints, a
/// warning will be given in debug mode.
///
/// The `debugTransformType` argument adds a debug label to this widget.
///
/// The `alignment`, `clipBehavior` and `constraintsTransform` arguments must
/// not be null.
const
ConstraintsTransformBox
({
Key
?
key
,
Widget
?
child
,
this
.
textDirection
,
this
.
alignment
=
Alignment
.
center
,
required
this
.
constraintsTransform
,
this
.
clipBehavior
=
Clip
.
none
,
String
debugTransformType
=
''
,
})
:
_debugTransformLabel
=
debugTransformType
,
assert
(
alignment
!=
null
),
assert
(
clipBehavior
!=
null
),
assert
(
constraintsTransform
!=
null
),
assert
(
debugTransformType
!=
null
),
super
(
key:
key
,
child:
child
);
/// A [BoxConstraintsTransform] that always returns its argument as-is (i.e.,
/// it is an identity function).
///
/// The [ConstraintsTransformBox] becomes a proxy widget that has no effect on
/// layout if [constraintsTransform] is set to this.
static
BoxConstraints
unmodified
(
BoxConstraints
constraints
)
=>
constraints
;
/// A [BoxConstraintsTransform] that always returns a [BoxConstraints] that
/// imposes no constraints on either dimension (i.e. `const BoxConstraints()`).
///
/// Setting [constraintsTransform] to this allows [child] to render at its
/// "natural" size (equivalent to an [UnconstrainedBox] with `constrainedAxis`
/// set to null).
static
BoxConstraints
unconstrained
(
BoxConstraints
constraints
)
=>
const
BoxConstraints
();
/// A [BoxConstraintsTransform] that removes the width constraints from the
/// input.
///
/// Setting [constraintsTransform] to this allows [child] to render at its
/// "natural" width (equivalent to an [UnconstrainedBox] with
/// `constrainedAxis` set to [Axis.horizontal]).
static
BoxConstraints
widthUnconstrained
(
BoxConstraints
constraints
)
=>
constraints
.
heightConstraints
();
/// A [BoxConstraintsTransform] that removes the height constraints from the
/// input.
///
/// Setting [constraintsTransform] to this allows [child] to render at its
/// "natural" height (equivalent to an [UnconstrainedBox] with
/// `constrainedAxis` set to [Axis.vertical]).
static
BoxConstraints
heightUnconstrained
(
BoxConstraints
constraints
)
=>
constraints
.
widthConstraints
();
/// A [BoxConstraintsTransform] that removes the `maxHeight` constraint from
/// the input.
///
/// Setting [constraintsTransform] to this allows [child] to render at its
/// "natural" height or the `minHeight` of the incoming [BoxConstraints],
/// whichever is larger.
static
BoxConstraints
maxHeightUnconstrained
(
BoxConstraints
constraints
)
=>
constraints
.
copyWith
(
maxHeight:
double
.
infinity
);
/// A [BoxConstraintsTransform] that removes the `maxWidth` constraint from
/// the input.
///
/// Setting [constraintsTransform] to this allows [child] to render at its
/// "natural" width or the `minWidth` of the incoming [BoxConstraints],
/// whichever is larger.
static
BoxConstraints
maxWidthUnconstrained
(
BoxConstraints
constraints
)
=>
constraints
.
copyWith
(
maxWidth:
double
.
infinity
);
/// A [BoxConstraintsTransform] that removes both the `maxWidth` and the
/// `maxHeight` constraints from the input.
///
/// Setting [constraintsTransform] to this allows [child] to render at least
/// its "natural" size, and grow along an axis if the incoming
/// [BoxConstraints] has a larger minimum constraint on that axis.
static
BoxConstraints
maxUnconstrained
(
BoxConstraints
constraints
)
=>
constraints
.
copyWith
(
maxWidth:
double
.
infinity
,
maxHeight:
double
.
infinity
);
static
final
Map
<
BoxConstraintsTransform
,
String
>
_debugKnownTransforms
=
<
BoxConstraintsTransform
,
String
>{
unmodified:
'unmodified'
,
unconstrained:
'unconstrained'
,
widthUnconstrained:
'width constraints removed'
,
heightUnconstrained:
'height constraints removed'
,
maxWidthUnconstrained:
'maxWidth constraint removed'
,
maxHeightUnconstrained:
'maxHeight constraint removed'
,
maxUnconstrained:
'maxWidth & maxHeight constraints removed'
,
};
/// The text direction to use when interpreting the [alignment] if it is an
/// [AlignmentDirectional].
///
/// Defaults to null, in which case [Directionality.maybeOf] is used to determine
/// the text direction.
final
TextDirection
?
textDirection
;
/// The alignment to use when laying out the child, if it has a different size
/// than this widget.
///
/// If this is an [AlignmentDirectional], then [textDirection] must not be
/// null.
///
/// See also:
///
/// * [Alignment] for non-[Directionality]-aware alignments.
/// * [AlignmentDirectional] for [Directionality]-aware alignments.
final
AlignmentGeometry
alignment
;
/// {@template flutter.widgets.constraintsTransform}
/// The function used to transform the incoming [BoxConstraints], to size
/// [child].
///
/// The function must return a [BoxConstraints] that is
/// [BoxConstraints.isNormalized].
///
/// See [ConstraintsTransformBox] for predefined common
/// [BoxConstraintsTransform]s.
/// {@endtemplate}
final
BoxConstraintsTransform
constraintsTransform
;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.none].
final
Clip
clipBehavior
;
final
String
_debugTransformLabel
;
@override
RenderConstraintsTransformBox
createRenderObject
(
BuildContext
context
)
{
return
RenderConstraintsTransformBox
(
textDirection:
textDirection
??
Directionality
.
maybeOf
(
context
),
alignment:
alignment
,
constraintsTransform:
constraintsTransform
,
clipBehavior:
clipBehavior
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderConstraintsTransformBox
renderObject
)
{
renderObject
..
textDirection
=
textDirection
??
Directionality
.
maybeOf
(
context
)
..
constraintsTransform
=
constraintsTransform
..
alignment
=
alignment
..
clipBehavior
=
clipBehavior
;
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
DiagnosticsProperty
<
AlignmentGeometry
>(
'alignment'
,
alignment
));
properties
.
add
(
EnumProperty
<
TextDirection
>(
'textDirection'
,
textDirection
,
defaultValue:
null
));
final
String
?
debugTransformLabel
=
_debugTransformLabel
.
isNotEmpty
?
_debugTransformLabel
:
_debugKnownTransforms
[
constraintsTransform
];
if
(
debugTransformLabel
!=
null
)
{
properties
.
add
(
DiagnosticsProperty
<
String
>(
'constraints transform'
,
debugTransformLabel
));
}
}
}
/// A widget that imposes no constraints on its child, allowing it to render
/// at its "natural" size.
///
...
...
@@ -2341,20 +2557,23 @@ class ConstrainedBox extends SingleChildRenderObjectWidget {
/// * [OverflowBox], a widget that imposes different constraints on its child
/// than it gets from its parent, possibly allowing the child to overflow
/// the parent.
class
UnconstrainedBox
extends
SingleChildRenderObjectWidget
{
/// * [ConstraintsTransformBox], a widget that sizes its child using a
/// transformed [BoxConstraints], and shows a warning if the child overflows
/// in debug mode.
class
UnconstrainedBox
extends
StatelessWidget
{
/// Creates a widget that imposes no constraints on its child, allowing it to
/// render at its "natural" size. If the child overflows the parents
/// constraints, a warning will be given in debug mode.
const
UnconstrainedBox
({
Key
?
key
,
Widget
?
child
,
this
.
child
,
this
.
textDirection
,
this
.
alignment
=
Alignment
.
center
,
this
.
constrainedAxis
,
this
.
clipBehavior
=
Clip
.
none
,
})
:
assert
(
alignment
!=
null
),
assert
(
clipBehavior
!=
null
),
super
(
key:
key
,
child:
child
);
super
(
key:
key
);
/// The text direction to use when interpreting the [alignment] if it is an
/// [AlignmentDirectional].
...
...
@@ -2384,22 +2603,34 @@ class UnconstrainedBox extends SingleChildRenderObjectWidget {
/// Defaults to [Clip.none].
final
Clip
clipBehavior
;
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderUnconstrainedBox
renderObject
)
{
renderObject
..
textDirection
=
textDirection
??
Directionality
.
maybeOf
(
context
)
..
alignment
=
alignment
..
constrainedAxis
=
constrainedAxis
..
clipBehavior
=
clipBehavior
;
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.ProxyWidget.child}
final
Widget
?
child
;
BoxConstraintsTransform
_axisToTransform
(
Axis
?
constrainedAxis
)
{
if
(
constrainedAxis
!=
null
)
{
switch
(
constrainedAxis
)
{
case
Axis
.
horizontal
:
return
ConstraintsTransformBox
.
heightUnconstrained
;
case
Axis
.
vertical
:
return
ConstraintsTransformBox
.
widthUnconstrained
;
}
}
else
{
return
ConstraintsTransformBox
.
unconstrained
;
}
}
@override
RenderUnconstrainedBox
createRenderObject
(
BuildContext
context
)
=>
RenderUnconstrainedBox
(
textDirection:
textDirection
??
Directionality
.
maybeOf
(
context
),
Widget
build
(
BuildContext
context
)
{
return
ConstraintsTransformBox
(
child:
child
,
textDirection:
textDirection
,
alignment:
alignment
,
constrainedAxis:
constrainedAxis
,
clipBehavior:
clipBehavior
,
constraintsTransform:
_axisToTransform
(
constrainedAxis
),
);
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
...
...
packages/flutter/test/rendering/box_test.dart
View file @
8c44abc0
...
...
@@ -378,6 +378,48 @@ void main() {
expect
(
unconstrained
.
getMaxIntrinsicWidth
(
100.0
),
equals
(
200.0
));
});
group
(
'ConstraintsTransfromBox'
,
()
{
FlutterErrorDetails
?
firstErrorDetails
;
void
exhaustErrors
()
{
FlutterErrorDetails
?
next
;
do
{
next
=
renderer
.
takeFlutterErrorDetails
();
firstErrorDetails
??=
next
;
}
while
(
next
!=
null
);
}
tearDown
(()
{
firstErrorDetails
=
null
;
});
test
(
'throws if the resulting constraints are not normalized'
,
()
{
final
RenderConstrainedBox
child
=
RenderConstrainedBox
(
additionalConstraints:
const
BoxConstraints
.
tightFor
(
height:
0
));
final
RenderConstraintsTransformBox
box
=
RenderConstraintsTransformBox
(
alignment:
Alignment
.
center
,
textDirection:
TextDirection
.
ltr
,
constraintsTransform:
(
BoxConstraints
constraints
)
=>
const
BoxConstraints
(
maxHeight:
-
1
,
minHeight:
200
),
child:
child
,
);
layout
(
box
,
constraints:
const
BoxConstraints
(),
onErrors:
exhaustErrors
);
expect
(
firstErrorDetails
?.
toString
(),
contains
(
'is not normalized'
));
});
test
(
'overflow is reported when insufficient size is given'
,
()
{
final
RenderConstrainedBox
child
=
RenderConstrainedBox
(
additionalConstraints:
const
BoxConstraints
.
tightFor
(
width:
double
.
maxFinite
));
final
RenderConstraintsTransformBox
box
=
RenderConstraintsTransformBox
(
alignment:
Alignment
.
center
,
textDirection:
TextDirection
.
ltr
,
constraintsTransform:
(
BoxConstraints
constraints
)
=>
constraints
.
copyWith
(
maxWidth:
double
.
infinity
),
child:
child
,
);
// No error reported.
layout
(
box
,
constraints:
const
BoxConstraints
(),
phase:
EnginePhase
.
composite
,
onErrors:
expectOverflowedErrors
);
});
});
test
(
'getMinIntrinsicWidth error handling'
,
()
{
final
RenderUnconstrainedBox
unconstrained
=
RenderUnconstrainedBox
(
textDirection:
TextDirection
.
ltr
,
...
...
packages/flutter/test/rendering/debug_overflow_indicator_test.dart
View file @
8c44abc0
...
...
@@ -36,7 +36,7 @@ void main() {
final
dynamic
exception
=
tester
.
takeException
();
expect
(
exception
,
isFlutterError
);
expect
(
exception
.
diagnostics
.
first
.
level
,
DiagnosticLevel
.
summary
);
expect
(
exception
.
diagnostics
.
first
.
toString
(),
startsWith
(
'A Render
Unconstrained
Box overflowed by '
));
expect
(
exception
.
diagnostics
.
first
.
toString
(),
startsWith
(
'A Render
ConstraintsTransform
Box overflowed by '
));
expect
(
find
.
byType
(
UnconstrainedBox
),
paints
..
rect
());
await
tester
.
pumpWidget
(
...
...
packages/flutter/test/widgets/basic_test.dart
View file @
8c44abc0
...
...
@@ -323,6 +323,7 @@ void main() {
const
UnconstrainedBox
(
constrainedAxis:
Axis
.
vertical
,).
toString
(),
equals
(
'UnconstrainedBox(alignment: Alignment.center, constrainedAxis: vertical)'
),
);
expect
(
const
UnconstrainedBox
(
constrainedAxis:
Axis
.
horizontal
,
textDirection:
TextDirection
.
rtl
,
alignment:
Alignment
.
topRight
).
toString
(),
equals
(
'UnconstrainedBox(alignment: Alignment.topRight, constrainedAxis: horizontal, textDirection: rtl)'
),
...
...
@@ -331,13 +332,32 @@ void main() {
testWidgets
(
'UnconstrainedBox can set and update clipBehavior'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
const
UnconstrainedBox
());
final
Render
UnconstrainedBox
renderObject
=
tester
.
allRenderObjects
.
whereType
<
RenderUnconstrained
Box
>().
first
;
final
Render
ConstraintsTransformBox
renderObject
=
tester
.
allRenderObjects
.
whereType
<
RenderConstraintsTransform
Box
>().
first
;
expect
(
renderObject
.
clipBehavior
,
equals
(
Clip
.
none
));
await
tester
.
pumpWidget
(
const
UnconstrainedBox
(
clipBehavior:
Clip
.
antiAlias
));
expect
(
renderObject
.
clipBehavior
,
equals
(
Clip
.
antiAlias
));
});
group
(
'ConstraintsTransformBox'
,
()
{
test
(
'toString'
,
()
{
expect
(
const
ConstraintsTransformBox
(
constraintsTransform:
ConstraintsTransformBox
.
unconstrained
,
).
toString
(),
equals
(
'ConstraintsTransformBox(alignment: Alignment.center, constraints transform: unconstrained)'
),
);
expect
(
const
ConstraintsTransformBox
(
textDirection:
TextDirection
.
rtl
,
alignment:
Alignment
.
topRight
,
constraintsTransform:
ConstraintsTransformBox
.
widthUnconstrained
,
).
toString
(),
equals
(
'ConstraintsTransformBox(alignment: Alignment.topRight, textDirection: rtl, constraints transform: width constraints removed)'
),
);
});
});
group
(
'ColoredBox'
,
()
{
late
_MockCanvas
mockCanvas
;
late
_MockPaintingContext
mockContext
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment