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
6a5964d8
Commit
6a5964d8
authored
Jan 13, 2020
by
Michael Goderbauer
Committed by
Flutter GitHub Bot
Jan 13, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make ParentDataWidget usable with different ancestor RenderObjectWidget types (#48541)
parent
8d438b03
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
319 additions
and
140 deletions
+319
-140
action_sheet.dart
packages/flutter/lib/src/cupertino/action_sheet.dart
+4
-1
dialog.dart
packages/flutter/lib/src/cupertino/dialog.dart
+4
-1
automatic_keep_alive.dart
packages/flutter/lib/src/widgets/automatic_keep_alive.dart
+8
-7
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+12
-3
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+122
-77
sliver.dart
packages/flutter/lib/src/widgets/sliver.dart
+4
-1
table.dart
packages/flutter/lib/src/widgets/table.dart
+4
-1
custom_multi_child_layout_test.dart
.../flutter/test/widgets/custom_multi_child_layout_test.dart
+4
-1
parent_data_test.dart
packages/flutter/test/widgets/parent_data_test.dart
+157
-48
No files found.
packages/flutter/lib/src/cupertino/action_sheet.dart
View file @
6a5964d8
...
@@ -955,7 +955,7 @@ class _PressableActionButtonState extends State<_PressableActionButton> {
...
@@ -955,7 +955,7 @@ class _PressableActionButtonState extends State<_PressableActionButton> {
// _ActionButtonParentData. _ActionButtonParentDataWidget is responsible for
// _ActionButtonParentData. _ActionButtonParentDataWidget is responsible for
// updating the pressed state of an _ActionButtonParentData based on the
// updating the pressed state of an _ActionButtonParentData based on the
// incoming isPressed property.
// incoming isPressed property.
class
_ActionButtonParentDataWidget
extends
ParentDataWidget
<
_
CupertinoAlertActionsRenderWidget
>
{
class
_ActionButtonParentDataWidget
extends
ParentDataWidget
<
_
ActionButtonParentData
>
{
const
_ActionButtonParentDataWidget
({
const
_ActionButtonParentDataWidget
({
Key
key
,
Key
key
,
this
.
isPressed
,
this
.
isPressed
,
...
@@ -977,6 +977,9 @@ class _ActionButtonParentDataWidget extends ParentDataWidget<_CupertinoAlertActi
...
@@ -977,6 +977,9 @@ class _ActionButtonParentDataWidget extends ParentDataWidget<_CupertinoAlertActi
targetParent
.
markNeedsPaint
();
targetParent
.
markNeedsPaint
();
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
_CupertinoAlertActionsRenderWidget
;
}
}
// ParentData applied to individual action buttons that report whether or not
// ParentData applied to individual action buttons that report whether or not
...
...
packages/flutter/lib/src/cupertino/dialog.dart
View file @
6a5964d8
...
@@ -1020,7 +1020,7 @@ class _PressableActionButtonState extends State<_PressableActionButton> {
...
@@ -1020,7 +1020,7 @@ class _PressableActionButtonState extends State<_PressableActionButton> {
// _ActionButtonParentData. _ActionButtonParentDataWidget is responsible for
// _ActionButtonParentData. _ActionButtonParentDataWidget is responsible for
// updating the pressed state of an _ActionButtonParentData based on the
// updating the pressed state of an _ActionButtonParentData based on the
// incoming [isPressed] property.
// incoming [isPressed] property.
class
_ActionButtonParentDataWidget
extends
ParentDataWidget
<
_
CupertinoDialogActionsRenderWidget
>
{
class
_ActionButtonParentDataWidget
extends
ParentDataWidget
<
_
ActionButtonParentData
>
{
const
_ActionButtonParentDataWidget
({
const
_ActionButtonParentDataWidget
({
Key
key
,
Key
key
,
this
.
isPressed
,
this
.
isPressed
,
...
@@ -1042,6 +1042,9 @@ class _ActionButtonParentDataWidget extends ParentDataWidget<_CupertinoDialogAct
...
@@ -1042,6 +1042,9 @@ class _ActionButtonParentDataWidget extends ParentDataWidget<_CupertinoDialogAct
targetParent
.
markNeedsPaint
();
targetParent
.
markNeedsPaint
();
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
_CupertinoDialogActionsRenderWidget
;
}
}
// ParentData applied to individual action buttons that report whether or not
// ParentData applied to individual action buttons that report whether or not
...
...
packages/flutter/lib/src/widgets/automatic_keep_alive.dart
View file @
6a5964d8
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
import
'dart:async'
;
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'framework.dart'
;
import
'framework.dart'
;
...
@@ -80,7 +81,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
...
@@ -80,7 +81,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
handle
.
addListener
(
_handles
[
handle
]);
handle
.
addListener
(
_handles
[
handle
]);
if
(!
_keepingAlive
)
{
if
(!
_keepingAlive
)
{
_keepingAlive
=
true
;
_keepingAlive
=
true
;
final
ParentDataElement
<
SliverWithKeepAliveWidget
>
childElement
=
_getChildElement
();
final
ParentDataElement
<
KeepAliveParentDataMixin
>
childElement
=
_getChildElement
();
if
(
childElement
!=
null
)
{
if
(
childElement
!=
null
)
{
// If the child already exists, update it synchronously.
// If the child already exists, update it synchronously.
_updateParentDataOfChild
(
childElement
);
_updateParentDataOfChild
(
childElement
);
...
@@ -92,7 +93,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
...
@@ -92,7 +93,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
if
(!
mounted
)
{
if
(!
mounted
)
{
return
;
return
;
}
}
final
ParentDataElement
<
SliverWithKeepAliveWidget
>
childElement
=
_getChildElement
();
final
ParentDataElement
<
KeepAliveParentDataMixin
>
childElement
=
_getChildElement
();
assert
(
childElement
!=
null
);
assert
(
childElement
!=
null
);
_updateParentDataOfChild
(
childElement
);
_updateParentDataOfChild
(
childElement
);
});
});
...
@@ -105,7 +106,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
...
@@ -105,7 +106,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
///
///
/// While this widget is guaranteed to have a child, this may return null if
/// While this widget is guaranteed to have a child, this may return null if
/// the first build of that child has not completed yet.
/// the first build of that child has not completed yet.
ParentDataElement
<
SliverWithKeepAliveWidget
>
_getChildElement
()
{
ParentDataElement
<
KeepAliveParentDataMixin
>
_getChildElement
()
{
assert
(
mounted
);
assert
(
mounted
);
final
Element
element
=
context
as
Element
;
final
Element
element
=
context
as
Element
;
Element
childElement
;
Element
childElement
;
...
@@ -131,12 +132,12 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
...
@@ -131,12 +132,12 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
element
.
visitChildren
((
Element
child
)
{
element
.
visitChildren
((
Element
child
)
{
childElement
=
child
;
childElement
=
child
;
});
});
assert
(
childElement
==
null
||
childElement
is
ParentDataElement
<
SliverWithKeepAliveWidget
>);
assert
(
childElement
==
null
||
childElement
is
ParentDataElement
<
KeepAliveParentDataMixin
>);
return
childElement
as
ParentDataElement
<
SliverWithKeepAliveWidget
>;
return
childElement
as
ParentDataElement
<
KeepAliveParentDataMixin
>;
}
}
void
_updateParentDataOfChild
(
ParentDataElement
<
SliverWithKeepAliveWidget
>
childElement
)
{
void
_updateParentDataOfChild
(
ParentDataElement
<
KeepAliveParentDataMixin
>
childElement
)
{
childElement
.
applyWidgetOutOfTurn
(
build
(
context
)
as
ParentDataWidget
<
SliverWithKeepAliveWidget
>);
childElement
.
applyWidgetOutOfTurn
(
build
(
context
)
as
ParentDataWidget
<
KeepAliveParentDataMixin
>);
}
}
VoidCallback
_createCallback
(
Listenable
handle
)
{
VoidCallback
_createCallback
(
Listenable
handle
)
{
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
6a5964d8
...
@@ -1910,7 +1910,7 @@ class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
...
@@ -1910,7 +1910,7 @@ class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
/// The [MultiChildLayoutDelegate.hasChild],
/// The [MultiChildLayoutDelegate.hasChild],
/// [MultiChildLayoutDelegate.layoutChild], and
/// [MultiChildLayoutDelegate.layoutChild], and
/// [MultiChildLayoutDelegate.positionChild] methods use these identifiers.
/// [MultiChildLayoutDelegate.positionChild] methods use these identifiers.
class
LayoutId
extends
ParentDataWidget
<
CustomMultiChildLayout
>
{
class
LayoutId
extends
ParentDataWidget
<
MultiChildLayoutParentData
>
{
/// Marks a child with a layout identifier.
/// Marks a child with a layout identifier.
///
///
/// Both the child and the id arguments must not be null.
/// Both the child and the id arguments must not be null.
...
@@ -1940,6 +1940,9 @@ class LayoutId extends ParentDataWidget<CustomMultiChildLayout> {
...
@@ -1940,6 +1940,9 @@ class LayoutId extends ParentDataWidget<CustomMultiChildLayout> {
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
CustomMultiChildLayout
;
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
@@ -3353,7 +3356,7 @@ class IndexedStack extends Stack {
...
@@ -3353,7 +3356,7 @@ class IndexedStack extends Stack {
/// * [PositionedTransition], which takes a provided [Animation] to transition
/// * [PositionedTransition], which takes a provided [Animation] to transition
/// changes in the child's position over a given duration.
/// changes in the child's position over a given duration.
/// * [PositionedDirectional], which adapts to the ambient [Directionality].
/// * [PositionedDirectional], which adapts to the ambient [Directionality].
class
Positioned
extends
ParentDataWidget
<
Stack
>
{
class
Positioned
extends
ParentDataWidget
<
Stack
ParentData
>
{
/// Creates a widget that controls where a child of a [Stack] is positioned.
/// Creates a widget that controls where a child of a [Stack] is positioned.
///
///
/// Only two out of the three horizontal values ([left], [right],
/// Only two out of the three horizontal values ([left], [right],
...
@@ -3577,6 +3580,9 @@ class Positioned extends ParentDataWidget<Stack> {
...
@@ -3577,6 +3580,9 @@ class Positioned extends ParentDataWidget<Stack> {
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
Stack
;
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
@@ -4363,7 +4369,7 @@ class Column extends Flex {
...
@@ -4363,7 +4369,7 @@ class Column extends Flex {
/// * [Expanded], which forces the child to expand to fill the available space.
/// * [Expanded], which forces the child to expand to fill the available space.
/// * [Spacer], a widget that takes up space proportional to it's flex value.
/// * [Spacer], a widget that takes up space proportional to it's flex value.
/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
class
Flexible
extends
ParentDataWidget
<
Flex
>
{
class
Flexible
extends
ParentDataWidget
<
Flex
ParentData
>
{
/// Creates a widget that controls how a child of a [Row], [Column], or [Flex]
/// Creates a widget that controls how a child of a [Row], [Column], or [Flex]
/// flexes.
/// flexes.
const
Flexible
({
const
Flexible
({
...
@@ -4413,6 +4419,9 @@ class Flexible extends ParentDataWidget<Flex> {
...
@@ -4413,6 +4419,9 @@ class Flexible extends ParentDataWidget<Flex> {
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
Flex
;
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
6a5964d8
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/sliver.dart
View file @
6a5964d8
...
@@ -1554,7 +1554,7 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement {
...
@@ -1554,7 +1554,7 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement {
/// In practice, the simplest way to deal with these notifications is to mix
/// In practice, the simplest way to deal with these notifications is to mix
/// [AutomaticKeepAliveClientMixin] into one's [State]. See the documentation
/// [AutomaticKeepAliveClientMixin] into one's [State]. See the documentation
/// for that mixin class for details.
/// for that mixin class for details.
class
KeepAlive
extends
ParentDataWidget
<
SliverWithKeepAliveWidget
>
{
class
KeepAlive
extends
ParentDataWidget
<
KeepAliveParentDataMixin
>
{
/// Marks a child as needing to remain alive.
/// Marks a child as needing to remain alive.
///
///
/// The [child] and [keepAlive] arguments must not be null.
/// The [child] and [keepAlive] arguments must not be null.
...
@@ -1590,6 +1590,9 @@ class KeepAlive extends ParentDataWidget<SliverWithKeepAliveWidget> {
...
@@ -1590,6 +1590,9 @@ class KeepAlive extends ParentDataWidget<SliverWithKeepAliveWidget> {
@override
@override
bool
debugCanApplyOutOfTurn
()
=>
keepAlive
;
bool
debugCanApplyOutOfTurn
()
=>
keepAlive
;
@override
Type
get
debugTypicalAncestorWidgetClass
=>
SliverWithKeepAliveWidget
;
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
...
packages/flutter/lib/src/widgets/table.dart
View file @
6a5964d8
...
@@ -354,7 +354,7 @@ class _TableElement extends RenderObjectElement {
...
@@ -354,7 +354,7 @@ class _TableElement extends RenderObjectElement {
/// the [TableCell] widget to its enclosing [Table] must contain only
/// the [TableCell] widget to its enclosing [Table] must contain only
/// [TableRow]s, [StatelessWidget]s, or [StatefulWidget]s (not
/// [TableRow]s, [StatelessWidget]s, or [StatefulWidget]s (not
/// other kinds of widgets, like [RenderObjectWidget]s).
/// other kinds of widgets, like [RenderObjectWidget]s).
class
TableCell
extends
ParentDataWidget
<
Table
>
{
class
TableCell
extends
ParentDataWidget
<
Table
CellParentData
>
{
/// Creates a widget that controls how a child of a [Table] is aligned.
/// Creates a widget that controls how a child of a [Table] is aligned.
const
TableCell
({
const
TableCell
({
Key
key
,
Key
key
,
...
@@ -376,6 +376,9 @@ class TableCell extends ParentDataWidget<Table> {
...
@@ -376,6 +376,9 @@ class TableCell extends ParentDataWidget<Table> {
}
}
}
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
Table
;
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
...
packages/flutter/test/widgets/custom_multi_child_layout_test.dart
View file @
6a5964d8
...
@@ -160,7 +160,7 @@ class InvalidConstraintsChildLayoutDelegate extends MultiChildLayoutDelegate {
...
@@ -160,7 +160,7 @@ class InvalidConstraintsChildLayoutDelegate extends MultiChildLayoutDelegate {
bool
shouldRelayout
(
MultiChildLayoutDelegate
oldDelegate
)
=>
true
;
bool
shouldRelayout
(
MultiChildLayoutDelegate
oldDelegate
)
=>
true
;
}
}
class
LayoutWithMissingId
extends
ParentDataWidget
<
CustomMultiChildLayout
>
{
class
LayoutWithMissingId
extends
ParentDataWidget
<
MultiChildLayoutParentData
>
{
const
LayoutWithMissingId
({
const
LayoutWithMissingId
({
Key
key
,
Key
key
,
@required
Widget
child
,
@required
Widget
child
,
...
@@ -169,6 +169,9 @@ class LayoutWithMissingId extends ParentDataWidget<CustomMultiChildLayout> {
...
@@ -169,6 +169,9 @@ class LayoutWithMissingId extends ParentDataWidget<CustomMultiChildLayout> {
@override
@override
void
applyParentData
(
RenderObject
renderObject
)
{}
void
applyParentData
(
RenderObject
renderObject
)
{}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
CustomMultiChildLayout
;
}
}
void
main
(
)
{
void
main
(
)
{
...
...
packages/flutter/test/widgets/parent_data_test.dart
View file @
6a5964d8
...
@@ -49,7 +49,6 @@ final TestParentData kNonPositioned = TestParentData();
...
@@ -49,7 +49,6 @@ final TestParentData kNonPositioned = TestParentData();
void
main
(
)
{
void
main
(
)
{
testWidgets
(
'ParentDataWidget control test'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'ParentDataWidget control test'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Stack
(
Stack
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
...
@@ -251,7 +250,9 @@ void main() {
...
@@ -251,7 +250,9 @@ void main() {
testWidgets
(
'ParentDataWidget conflicting data'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'ParentDataWidget conflicting data'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Stack
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Stack
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
children:
const
<
Widget
>[
children:
const
<
Widget
>[
Positioned
(
Positioned
(
...
@@ -265,19 +266,23 @@ void main() {
...
@@ -265,19 +266,23 @@ void main() {
),
),
],
],
),
),
),
);
);
dynamic
exception
=
tester
.
takeException
();
dynamic
exception
=
tester
.
takeException
();
expect
(
exception
,
isFlutterError
);
expect
(
exception
,
isFlutterError
);
expect
(
expect
(
exception
.
toString
(),
exception
.
toString
(),
equalsIgnoringHashCodes
(
equalsIgnoringHashCodes
(
'Incorrect use of ParentDataWidget.
\n
'
'Incorrect use of ParentDataWidget.
\n
'
'Positioned widgets must be placed directly inside Stack widgets.
\n
'
'The following ParentDataWidgets are providing parent data to the same RenderObject:
\n
'
'Positioned(no depth, left: 7.0, top: 6.0, dirty) has a Stack ancestor, but there are other widgets between them:
\n
'
'- Positioned(left: 7.0, top: 6.0) (typically placed directly inside a Stack widget)
\n
'
'- Positioned(top: 5.0, bottom: 8.0) (this is a different Positioned than the one with the problem)
\n
'
'- Positioned(top: 5.0, bottom: 8.0) (typically placed directly inside a Stack widget)
\n
'
'These widgets cannot come between a Positioned and its Stack.
\n
'
'However, a RenderObject can only receive parent data from at most one ParentDataWidget.
\n
'
'The ownership chain for the parent of the offending Positioned was:
\n
'
'Usually, this indicates that at least one of the offending ParentDataWidgets listed '
' Positioned ← Stack ← [root]'
'above is not placed directly inside a compatible ancestor widget.
\n
'
'The ownership chain for the RenderObject that received the parent data was:
\n
'
' DecoratedBox ← Positioned ← Positioned ← Stack ← Directionality ← [root]'
),
),
);
);
...
@@ -286,7 +291,9 @@ void main() {
...
@@ -286,7 +291,9 @@ void main() {
checkTree
(
tester
,
<
TestParentData
>[]);
checkTree
(
tester
,
<
TestParentData
>[]);
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
Container
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
child:
Row
(
child:
Row
(
children:
const
<
Widget
>[
children:
const
<
Widget
>[
Positioned
(
Positioned
(
...
@@ -297,6 +304,7 @@ void main() {
...
@@ -297,6 +304,7 @@ void main() {
],
],
),
),
),
),
),
);
);
exception
=
tester
.
takeException
();
exception
=
tester
.
takeException
();
expect
(
exception
,
isFlutterError
);
expect
(
exception
,
isFlutterError
);
...
@@ -304,10 +312,14 @@ void main() {
...
@@ -304,10 +312,14 @@ void main() {
exception
.
toString
(),
exception
.
toString
(),
equalsIgnoringHashCodes
(
equalsIgnoringHashCodes
(
'Incorrect use of ParentDataWidget.
\n
'
'Incorrect use of ParentDataWidget.
\n
'
'Positioned widgets must be placed inside Stack widgets.
\n
'
'The ParentDataWidget Positioned(left: 7.0, top: 6.0) wants to apply ParentData of type '
'Positioned(no depth, left: 7.0, top: 6.0, dirty) has no Stack ancestor at all.
\n
'
'StackParentData to a RenderObject, which has been set up to accept ParentData of '
'The ownership chain for the parent of the offending Positioned was:
\n
'
'incompatible type FlexParentData.
\n
'
' Row ← Container ← [root]'
'Usually, this means that the Positioned widget has the wrong ancestor RenderObjectWidget. '
'Typically, Positioned widgets are placed directly inside Stack widgets.
\n
'
'The offending Positioned is currently placed inside a Row widget.
\n
'
'The ownership chain for the RenderObject that received the incompatible parent data was:
\n
'
' DecoratedBox ← Positioned ← Row ← Container ← Directionality ← [root]'
),
),
);
);
...
@@ -377,7 +389,9 @@ void main() {
...
@@ -377,7 +389,9 @@ void main() {
});
});
testWidgets
(
'Parent data invalid ancestor'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Parent data invalid ancestor'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Row
(
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Row
(
children:
<
Widget
>[
children:
<
Widget
>[
Stack
(
Stack
(
textDirection:
TextDirection
.
ltr
,
textDirection:
TextDirection
.
ltr
,
...
@@ -388,6 +402,7 @@ void main() {
...
@@ -388,6 +402,7 @@ void main() {
],
],
),
),
],
],
),
));
));
final
dynamic
exception
=
tester
.
takeException
();
final
dynamic
exception
=
tester
.
takeException
();
...
@@ -396,13 +411,107 @@ void main() {
...
@@ -396,13 +411,107 @@ void main() {
exception
.
toString
(),
exception
.
toString
(),
equalsIgnoringHashCodes
(
equalsIgnoringHashCodes
(
'Incorrect use of ParentDataWidget.
\n
'
'Incorrect use of ParentDataWidget.
\n
'
'Expanded widgets must be placed directly inside Flex widgets.
\n
'
'The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type '
'Expanded(no depth, flex: 1, dirty) has a Flex ancestor, but there are other widgets between them:
\n
'
'FlexParentData to a RenderObject, which has been set up to accept ParentData of '
'- Stack(alignment: AlignmentDirectional.topStart, textDirection: ltr, fit: loose, overflow: clip)
\n
'
'incompatible type StackParentData.
\n
'
'These widgets cannot come between a Expanded and its Flex.
\n
'
'Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. '
'The ownership chain for the parent of the offending Expanded was:
\n
'
'Typically, Expanded widgets are placed directly inside Flex widgets.
\n
'
' Stack ← Row ← [root]'
'The offending Expanded is currently placed inside a Stack widget.
\n
'
'The ownership chain for the RenderObject that received the incompatible parent data was:
\n
'
' LimitedBox ← Container ← Expanded ← Stack ← Row ← Directionality ← [root]'
),
),
);
);
});
});
testWidgets
(
'ParentDataWidget can be used with different ancestor RenderObjectWidgets'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
OneAncestorWidget
(
child:
Container
(),
),
);
DummyParentData
parentData
=
tester
.
renderObject
(
find
.
byType
(
Container
)).
parentData
as
DummyParentData
;
expect
(
parentData
.
string
,
isNull
);
await
tester
.
pumpWidget
(
OneAncestorWidget
(
child:
TestParentDataWidget
(
string:
'Foo'
,
child:
Container
(),
),
),
);
parentData
=
tester
.
renderObject
(
find
.
byType
(
Container
)).
parentData
as
DummyParentData
;
expect
(
parentData
.
string
,
'Foo'
);
await
tester
.
pumpWidget
(
AnotherAncestorWidget
(
child:
TestParentDataWidget
(
string:
'Bar'
,
child:
Container
(),
),
),
);
parentData
=
tester
.
renderObject
(
find
.
byType
(
Container
)).
parentData
as
DummyParentData
;
expect
(
parentData
.
string
,
'Bar'
);
});
}
class
TestParentDataWidget
extends
ParentDataWidget
<
DummyParentData
>
{
const
TestParentDataWidget
({
Key
key
,
this
.
string
,
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
final
String
string
;
@override
void
applyParentData
(
RenderObject
renderObject
)
{
assert
(
renderObject
.
parentData
is
DummyParentData
);
final
DummyParentData
parentData
=
renderObject
.
parentData
as
DummyParentData
;
parentData
.
string
=
string
;
}
@override
Type
get
debugTypicalAncestorWidgetClass
=>
OneAncestorWidget
;
}
class
DummyParentData
extends
ParentData
{
String
string
;
}
class
OneAncestorWidget
extends
SingleChildRenderObjectWidget
{
const
OneAncestorWidget
({
Key
key
,
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
@override
RenderOne
createRenderObject
(
BuildContext
context
)
=>
RenderOne
();
}
class
AnotherAncestorWidget
extends
SingleChildRenderObjectWidget
{
const
AnotherAncestorWidget
({
Key
key
,
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
@override
RenderAnother
createRenderObject
(
BuildContext
context
)
=>
RenderAnother
();
}
class
RenderOne
extends
RenderProxyBox
{
@override
void
setupParentData
(
RenderBox
child
)
{
if
(
child
.
parentData
is
!
DummyParentData
)
child
.
parentData
=
DummyParentData
();
}
}
class
RenderAnother
extends
RenderProxyBox
{
@override
void
setupParentData
(
RenderBox
child
)
{
if
(
child
.
parentData
is
!
DummyParentData
)
child
.
parentData
=
DummyParentData
();
}
}
}
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