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
7df2dfca
Commit
7df2dfca
authored
Dec 31, 2015
by
Ian Hickson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve diagnostics around misuse of ParentDataWidgets.
Fixes
https://github.com/flutter/flutter/issues/572
parent
24cdc2cc
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
68 additions
and
38 deletions
+68
-38
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+12
-26
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+56
-12
No files found.
packages/flutter/lib/src/widgets/basic.dart
View file @
7df2dfca
...
...
@@ -432,7 +432,7 @@ class CustomOneChildLayout extends OneChildRenderObjectWidget {
}
/// Metadata for identifying children in a [CustomMultiChildLayout].
class
LayoutId
extends
ParentDataWidget
{
class
LayoutId
extends
ParentDataWidget
<
CustomMultiChildLayout
>
{
LayoutId
({
Key
key
,
Widget
child
,
...
...
@@ -445,13 +445,6 @@ class LayoutId extends ParentDataWidget {
/// An object representing the identity of this child.
final
Object
id
;
void
debugValidateAncestor
(
Widget
ancestor
)
{
assert
(()
{
'LayoutId must placed inside a CustomMultiChildLayout'
;
return
ancestor
is
CustomMultiChildLayout
;
});
}
void
applyParentData
(
RenderObject
renderObject
)
{
assert
(
renderObject
.
parentData
is
MultiChildLayoutParentData
);
final
MultiChildLayoutParentData
parentData
=
renderObject
.
parentData
;
...
...
@@ -967,11 +960,18 @@ class BlockBody extends MultiChildRenderObjectWidget {
}
}
abstract
class
StackRenderObjectWidgetBase
extends
MultiChildRenderObjectWidget
{
StackRenderObjectWidgetBase
({
List
<
Widget
>
children
,
Key
key
})
:
super
(
key:
key
,
children:
children
);
}
/// Uses the stack layout algorithm for its children.
///
/// For details about the stack layout algorithm, see [RenderStack]. To control
/// the position of child widgets, see the [Positioned] widget.
class
Stack
extends
MultiChildRenderObjectWidget
{
class
Stack
extends
StackRenderObjectWidgetBase
{
Stack
(
List
<
Widget
>
children
,
{
Key
key
,
this
.
alignment
:
const
FractionalOffset
(
0.0
,
0.0
)
...
...
@@ -988,7 +988,7 @@ class Stack extends MultiChildRenderObjectWidget {
}
/// A [Stack] that shows a single child at once.
class
IndexedStack
extends
MultiChildRenderObjectWidget
{
class
IndexedStack
extends
StackRenderObjectWidgetBase
{
IndexedStack
(
List
<
Widget
>
children
,
{
Key
key
,
this
.
alignment
:
const
FractionalOffset
(
0.0
,
0.0
),
...
...
@@ -1017,7 +1017,7 @@ class IndexedStack extends MultiChildRenderObjectWidget {
/// This widget must be a descendant of a [Stack], and the path from this widget
/// to its enclosing [Stack] must contain only components (e.g., not other
/// kinds of widgets, like [RenderObjectWidget]s).
class
Positioned
extends
ParentDataWidget
{
class
Positioned
extends
ParentDataWidget
<
StackRenderObjectWidgetBase
>
{
Positioned
({
Key
key
,
Widget
child
,
...
...
@@ -1066,13 +1066,6 @@ class Positioned extends ParentDataWidget {
/// Ignored if both top and bottom are non-null.
final
double
height
;
void
debugValidateAncestor
(
Widget
ancestor
)
{
assert
(()
{
'Positioned must placed inside a Stack'
;
return
ancestor
is
Stack
;
});
}
void
applyParentData
(
RenderObject
renderObject
)
{
assert
(
renderObject
.
parentData
is
StackParentData
);
final
StackParentData
parentData
=
renderObject
.
parentData
;
...
...
@@ -1214,7 +1207,7 @@ class Column extends Flex {
/// path from this widget to its enclosing [Flex], [Row], or [Column] must
/// contain only components (e.g., not other kinds of widgets, like
/// [RenderObjectWidget]s).
class
Flexible
extends
ParentDataWidget
{
class
Flexible
extends
ParentDataWidget
<
Flex
>
{
Flexible
({
Key
key
,
this
.
flex
:
1
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
...
...
@@ -1226,13 +1219,6 @@ class Flexible extends ParentDataWidget {
/// according to the flex factors of the flexible children.
final
int
flex
;
void
debugValidateAncestor
(
Widget
ancestor
)
{
assert
(()
{
'Flexible must placed inside a Flex'
;
return
ancestor
is
Flex
;
});
}
void
applyParentData
(
RenderObject
renderObject
)
{
assert
(
renderObject
.
parentData
is
FlexParentData
);
final
FlexParentData
parentData
=
renderObject
.
parentData
;
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
7df2dfca
...
...
@@ -446,17 +446,50 @@ abstract class _ProxyComponent extends Widget {
final
Widget
child
;
}
abstract
class
ParentDataWidget
extends
_ProxyComponent
{
abstract
class
ParentDataWidget
<
T
extends
RenderObjectWidget
>
extends
_ProxyComponent
{
const
ParentDataWidget
({
Key
key
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
ParentDataElement
createElement
()
=>
new
ParentDataElement
(
this
);
/// Subclasses should override this function to ensure that they are placed
/// inside widgets that expect them.
/// Subclasses should override this function to return true if the given
/// ancestor is a RenderObjectWidget that wraps a RenderObject that can handle
/// the kind of ParentData widget that the ParentDataWidget subclass handles.
///
/// The given ancestor is the first RenderObjectWidget ancestor of this widget.
void
debugValidateAncestor
(
RenderObjectWidget
ancestor
);
/// The default implementation uses the type argument.
bool
debugIsValidAncestor
(
RenderObjectWidget
ancestor
)
{
assert
(
T
!=
dynamic
);
assert
(
T
!=
RenderObjectWidget
);
return
ancestor
is
T
;
}
/// Subclasses should override this to describe the requirements for using the
/// ParentDataWidget subclass. It is called when debugIsValidAncestor()
/// returned false for an ancestor, or when there are extraneous
/// ParentDataWidgets in the ancestor chain.
String
debugDescribeInvalidAncestorChain
({
String
description
,
String
ownershipChain
,
bool
foundValidAncestor
,
Iterable
<
Widget
>
badAncestors
})
{
assert
(
T
!=
dynamic
);
assert
(
T
!=
RenderObjectWidget
);
String
result
;
if
(!
foundValidAncestor
)
{
result
=
'
$runtimeType
widgets must be placed inside
$T
widgets.
\n
'
'
$description
has no
$T
ancestor at all.
\n
'
;
}
else
{
assert
(
badAncestors
.
isNotEmpty
);
result
=
'
$runtimeType
widgets must be placed directly inside
$T
widgets.
\n
'
'
$description
has a
$T
ancestor, but there are other widgets between them:
\n
'
;
for
(
Widget
ancestor
in
badAncestors
)
{
if
(
ancestor
.
runtimeType
==
runtimeType
)
{
result
+=
'
$ancestor
(this is a different
$runtimeType
than the one with the problem)
\n
'
;
}
else
{
result
+=
'
$ancestor
\n
'
;
}
}
result
+=
'These widgets cannot come between a
$runtimeType
and its
$T
.
\n
'
;
}
result
+=
'The ownership chain for the parent of the offending
$runtimeType
was:
\n
$ownershipChain
'
;
return
result
;
}
void
applyParentData
(
RenderObject
renderObject
);
}
...
...
@@ -1286,16 +1319,27 @@ class ParentDataElement extends _ProxyElement<ParentDataWidget> {
void
mount
(
Element
parent
,
dynamic
slot
)
{
assert
(()
{
List
<
Widget
>
badAncestors
=
<
Widget
>[];
Element
ancestor
=
parent
;
while
(
ancestor
is
!
RenderObjectElement
)
{
assert
(
ancestor
!=
null
);
assert
(()
{
'You cannot nest parent data widgets inside one another.'
;
return
ancestor
is
!
ParentDataElement
;
});
while
(
ancestor
!=
null
)
{
if
(
ancestor
is
ParentDataElement
)
{
badAncestors
.
add
(
ancestor
.
widget
);
}
else
if
(
ancestor
is
RenderObjectElement
)
{
if
(
widget
.
debugIsValidAncestor
(
ancestor
.
widget
))
break
;
badAncestors
.
add
(
ancestor
.
widget
);
}
ancestor
=
ancestor
.
_parent
;
}
_widget
.
debugValidateAncestor
(
ancestor
.
_widget
);
if
(
ancestor
!=
null
&&
badAncestors
.
isEmpty
)
return
true
;
debugPrint
(
widget
.
debugDescribeInvalidAncestorChain
(
description:
"
$this
"
,
ownershipChain:
parent
.
debugGetOwnershipChain
(
10
),
foundValidAncestor:
ancestor
!=
null
,
badAncestors:
badAncestors
));
assert
(
'Incorrect use of ParentDataWidget. See console log for details.'
==
true
);
return
true
;
});
super
.
mount
(
parent
,
slot
);
...
...
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