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
663596bc
Commit
663596bc
authored
Sep 01, 2016
by
Ian Hickson
Committed by
GitHub
Sep 01, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Handle GlobalKey reparenting inside LayoutBuilder (#5673)
parent
3732d754
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
202 additions
and
19 deletions
+202
-19
flexible_space_bar.dart
packages/flutter/lib/src/material/flexible_space_bar.dart
+1
-0
object.dart
packages/flutter/lib/src/rendering/object.dart
+39
-3
layout_builder.dart
packages/flutter/lib/src/widgets/layout_builder.dart
+26
-15
scroll_behavior.dart
packages/flutter/lib/src/widgets/scroll_behavior.dart
+1
-1
layout_builder_and_parent_data_test.dart
...tter/test/widget/layout_builder_and_parent_data_test.dart
+73
-0
layout_builder_mutations_test.dart
...es/flutter/test/widget/layout_builder_mutations_test.dart
+62
-0
No files found.
packages/flutter/lib/src/material/flexible_space_bar.dart
View file @
663596bc
...
@@ -91,6 +91,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
...
@@ -91,6 +91,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
if
(
config
.
background
!=
null
)
{
if
(
config
.
background
!=
null
)
{
final
double
fadeStart
=
math
.
max
(
0.0
,
1.0
-
kToolBarHeight
/
deltaHeight
);
final
double
fadeStart
=
math
.
max
(
0.0
,
1.0
-
kToolBarHeight
/
deltaHeight
);
final
double
fadeEnd
=
1.0
;
final
double
fadeEnd
=
1.0
;
assert
(
fadeStart
<=
fadeEnd
);
final
double
opacity
=
1.0
-
new
Interval
(
fadeStart
,
fadeEnd
).
transform
(
t
);
final
double
opacity
=
1.0
-
new
Interval
(
fadeStart
,
fadeEnd
).
transform
(
t
);
final
double
parallax
=
new
Tween
<
double
>(
begin:
0.0
,
end:
deltaHeight
/
4.0
).
lerp
(
t
);
final
double
parallax
=
new
Tween
<
double
>(
begin:
0.0
,
end:
deltaHeight
/
4.0
).
lerp
(
t
);
if
(
opacity
>
0.0
)
{
if
(
opacity
>
0.0
)
{
...
...
packages/flutter/lib/src/rendering/object.dart
View file @
663596bc
...
@@ -880,6 +880,25 @@ class PipelineOwner {
...
@@ -880,6 +880,25 @@ class PipelineOwner {
}
}
}
}
// This flag is used to allow the kinds of mutations performed by GlobalKey
// reparenting while a LayoutBuilder is being rebuilt and in so doing tries to
// move a node from another LayoutBuilder subtree that hasn't been updated
// yet. To set this, call [_enableMutationsToDirtySubtrees], which is called
// by [RenderObject.invokeLayoutCallback].
bool
_debugAllowMutationsToDirtySubtrees
=
false
;
// See [RenderObject.invokeLayoutCallback].
void
_enableMutationsToDirtySubtrees
(
VoidCallback
callback
)
{
assert
(
_debugDoingLayout
);
bool
oldState
=
_debugAllowMutationsToDirtySubtrees
;
_debugAllowMutationsToDirtySubtrees
=
true
;
try
{
callback
();
}
finally
{
_debugAllowMutationsToDirtySubtrees
=
oldState
;
}
}
List
<
RenderObject
>
_nodesNeedingCompositingBitsUpdate
=
<
RenderObject
>[];
List
<
RenderObject
>
_nodesNeedingCompositingBitsUpdate
=
<
RenderObject
>[];
/// Updates the [needsCompositing] bits.
/// Updates the [needsCompositing] bits.
///
///
...
@@ -1174,6 +1193,10 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
...
@@ -1174,6 +1193,10 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
result
=
true
;
result
=
true
;
break
;
break
;
}
}
if
(
owner
!=
null
&&
owner
.
_debugAllowMutationsToDirtySubtrees
&&
node
.
_needsLayout
)
{
result
=
true
;
break
;
}
if
(
node
.
_debugMutationsLocked
)
{
if
(
node
.
_debugMutationsLocked
)
{
result
=
false
;
result
=
false
;
break
;
break
;
...
@@ -1584,8 +1607,21 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
...
@@ -1584,8 +1607,21 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// this field always holds a closure.
// this field always holds a closure.
VoidCallback
_performLayout
=
_doNothing
;
VoidCallback
_performLayout
=
_doNothing
;
/// Allows this render object to mutate its child list during layout and
/// Allows mutations to be made to this object's child list (and any
/// calls callback.
/// descendants) as well as to any other dirty nodes in the render tree owned
/// by the same [PipelineOwner] as this object. The `callback` argument is
/// invoked synchronously, and the mutations are allowed only during that
/// callback's execution.
///
/// This exists to allow child lists to be built on-demand during layout (e.g.
/// based on the object's size), and to enable nodes to be moved around the
/// tree as this happens (e.g. to handle [GlobalKey] reparenting), while still
/// ensuring that any particular node is only laid out once per frame.
///
/// Calling this function disables a number of assertions that are intended to
/// catch likely bugs. As such, using this function is generally discouraged.
///
/// This function can only be called during layout.
@protected
@protected
void
invokeLayoutCallback
(
LayoutCallback
callback
)
{
void
invokeLayoutCallback
(
LayoutCallback
callback
)
{
assert
(
_debugMutationsLocked
);
assert
(
_debugMutationsLocked
);
...
@@ -1593,7 +1629,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
...
@@ -1593,7 +1629,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert
(!
_doingThisLayoutWithCallback
);
assert
(!
_doingThisLayoutWithCallback
);
_doingThisLayoutWithCallback
=
true
;
_doingThisLayoutWithCallback
=
true
;
try
{
try
{
callback
(
constraints
);
owner
.
_enableMutationsToDirtySubtrees
(()
{
callback
(
constraints
);
}
);
}
finally
{
}
finally
{
_doingThisLayoutWithCallback
=
false
;
_doingThisLayoutWithCallback
=
false
;
}
}
...
...
packages/flutter/lib/src/widgets/layout_builder.dart
View file @
663596bc
...
@@ -48,10 +48,14 @@ class LayoutBuilder extends RenderObjectWidget {
...
@@ -48,10 +48,14 @@ class LayoutBuilder extends RenderObjectWidget {
@override
@override
_RenderLayoutBuilder
createRenderObject
(
BuildContext
context
)
=>
new
_RenderLayoutBuilder
();
_RenderLayoutBuilder
createRenderObject
(
BuildContext
context
)
=>
new
_RenderLayoutBuilder
();
// updateRenderObject is redundant with the logic in the LayoutBuilderElement below.
}
}
class
_RenderLayoutBuilder
extends
RenderBox
with
RenderObjectWithChildMixin
<
RenderBox
>
{
class
_RenderLayoutBuilder
extends
RenderBox
with
RenderObjectWithChildMixin
<
RenderBox
>
{
_RenderLayoutBuilder
({
LayoutCallback
callback
})
:
_callback
=
callback
;
_RenderLayoutBuilder
({
LayoutCallback
callback
,
})
:
_callback
=
callback
;
LayoutCallback
get
callback
=>
_callback
;
LayoutCallback
get
callback
=>
_callback
;
LayoutCallback
_callback
;
LayoutCallback
_callback
;
...
@@ -102,8 +106,8 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
...
@@ -102,8 +106,8 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
@override
@override
void
performLayout
()
{
void
performLayout
()
{
if
(
callback
!=
null
)
assert
(
callback
!=
null
);
invokeLayoutCallback
(
callback
);
invokeLayoutCallback
(
callback
);
if
(
child
!=
null
)
{
if
(
child
!=
null
)
{
child
.
layout
(
constraints
,
parentUsesSize:
true
);
child
.
layout
(
constraints
,
parentUsesSize:
true
);
size
=
constraints
.
constrain
(
child
.
size
);
size
=
constraints
.
constrain
(
child
.
size
);
...
@@ -124,6 +128,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
...
@@ -124,6 +128,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
}
}
}
}
// TODO(ianh): move this class up to just below its widget.
class
_LayoutBuilderElement
extends
RenderObjectElement
{
class
_LayoutBuilderElement
extends
RenderObjectElement
{
_LayoutBuilderElement
(
LayoutBuilder
widget
)
:
super
(
widget
);
_LayoutBuilderElement
(
LayoutBuilder
widget
)
:
super
(
widget
);
...
@@ -144,7 +149,7 @@ class _LayoutBuilderElement extends RenderObjectElement {
...
@@ -144,7 +149,7 @@ class _LayoutBuilderElement extends RenderObjectElement {
@override
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
// Creates the renderObject.
super
.
mount
(
parent
,
newSlot
);
// Creates the renderObject.
renderObject
.
callback
=
_layout
;
// The _child will be built during layout.
renderObject
.
callback
=
_layout
;
}
}
@override
@override
...
@@ -161,7 +166,7 @@ class _LayoutBuilderElement extends RenderObjectElement {
...
@@ -161,7 +166,7 @@ class _LayoutBuilderElement extends RenderObjectElement {
// This gets called if markNeedsBuild() is called on us.
// This gets called if markNeedsBuild() is called on us.
// That might happen if, e.g., our builder uses Inherited widgets.
// That might happen if, e.g., our builder uses Inherited widgets.
renderObject
.
markNeedsLayout
();
renderObject
.
markNeedsLayout
();
super
.
performRebuild
();
//
calls widget.updateRenderObject
super
.
performRebuild
();
//
Calls widget.updateRenderObject (a no-op in this case).
}
}
@override
@override
...
@@ -171,18 +176,24 @@ class _LayoutBuilderElement extends RenderObjectElement {
...
@@ -171,18 +176,24 @@ class _LayoutBuilderElement extends RenderObjectElement {
}
}
void
_layout
(
BoxConstraints
constraints
)
{
void
_layout
(
BoxConstraints
constraints
)
{
if
(
widget
.
builder
==
null
)
Widget
built
;
return
;
if
(
widget
.
builder
!=
null
)
{
owner
.
lockState
(()
{
try
{
built
=
widget
.
builder
(
this
,
constraints
);
debugWidgetBuilderValue
(
widget
,
built
);
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$widget
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
}
});
}
owner
.
lockState
(()
{
owner
.
lockState
(()
{
Widget
built
;
if
(
widget
.
builder
==
null
)
{
try
{
if
(
_child
!=
null
)
built
=
widget
.
builder
(
this
,
constraints
);
_child
=
updateChild
(
_child
,
null
,
null
);
debugWidgetBuilderValue
(
widget
,
built
);
return
;
}
catch
(
e
,
stack
)
{
_debugReportException
(
'building
$widget
'
,
e
,
stack
);
built
=
new
ErrorWidget
(
e
);
}
}
try
{
try
{
_child
=
updateChild
(
_child
,
built
,
null
);
_child
=
updateChild
(
_child
,
built
,
null
);
assert
(
_child
!=
null
);
assert
(
_child
!=
null
);
...
...
packages/flutter/lib/src/widgets/scroll_behavior.dart
View file @
663596bc
...
@@ -66,7 +66,7 @@ abstract class ScrollBehavior<T, U> {
...
@@ -66,7 +66,7 @@ abstract class ScrollBehavior<T, U> {
/// from the given offset by the given delta.
/// from the given offset by the given delta.
T
applyCurve
(
T
scrollOffset
,
T
scrollDelta
)
=>
scrollOffset
;
T
applyCurve
(
T
scrollOffset
,
T
scrollDelta
)
=>
scrollOffset
;
/// Whether this scroll behavior currently permits scrolling
/// Whether this scroll behavior currently permits scrolling
.
bool
get
isScrollable
=>
true
;
bool
get
isScrollable
=>
true
;
/// The scroll drag constant to use for physics simulations created by this
/// The scroll drag constant to use for physics simulations created by this
...
...
packages/flutter/test/widget/layout_builder_and_parent_data_test.dart
0 → 100644
View file @
663596bc
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter_test/flutter_test.dart'
hide
TypeMatcher
;
import
'package:flutter/widgets.dart'
;
class
SizeChanger
extends
StatefulWidget
{
SizeChanger
({
Key
key
,
this
.
child
,
})
:
super
(
key:
key
);
final
Widget
child
;
@override
SizeChangerState
createState
()
=>
new
SizeChangerState
();
}
class
SizeChangerState
extends
State
<
SizeChanger
>
{
bool
_flag
=
false
;
void
trigger
()
{
setState
(()
{
_flag
=
true
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
new
Row
(
children:
<
Widget
>[
new
SizedBox
(
height:
_flag
?
50.0
:
100.0
,
width:
100.0
,
child:
config
.
child
)
],
);
}
}
class
Wrapper
extends
StatelessWidget
{
Wrapper
({
Key
key
,
this
.
child
,
})
:
super
(
key:
key
);
final
Widget
child
;
@override
Widget
build
(
BuildContext
context
)
{
return
child
;
}
}
void
main
(
)
{
testWidgets
(
'Applying parent data inside a LayoutBuilder'
,
(
WidgetTester
tester
)
async
{
int
frame
=
0
;
await
tester
.
pumpWidget
(
new
SizeChanger
(
// when this is triggered, the child LayoutBuilder will build again
child:
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
Column
(
children:
<
Widget
>[
new
Flexible
(
flex:
frame
,
// this is different after the next pump, so that the parentData has to be applied again
child:
new
Container
(
height:
100.0
),
)]);
})
));
frame
+=
1
;
SizeChangerState
state
=
tester
.
state
(
find
.
byType
(
SizeChanger
));
state
.
trigger
();
await
tester
.
pump
();
});
}
packages/flutter/test/widget/layout_builder_mutations_test.dart
0 → 100644
View file @
663596bc
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/src/widgets/basic.dart'
;
import
'package:flutter/src/widgets/framework.dart'
;
import
'package:flutter/src/widgets/layout_builder.dart'
;
import
'package:flutter_test/flutter_test.dart'
hide
TypeMatcher
;
class
Wrapper
extends
StatelessWidget
{
Wrapper
({
Key
key
,
this
.
child
})
:
super
(
key:
key
)
{
assert
(
child
!=
null
);
}
final
Widget
child
;
@override
Widget
build
(
BuildContext
context
)
=>
child
;
}
void
main
(
)
{
testWidgets
(
'Moving a global key from another LayoutBuilder at layout time'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
victimKey
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
Row
(
children:
<
Widget
>[
new
Wrapper
(
child:
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
SizedBox
();
}),
),
new
Wrapper
(
child:
new
Wrapper
(
child:
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
Wrapper
(
child:
new
SizedBox
(
key:
victimKey
)
);
})
)
),
]));
await
tester
.
pumpWidget
(
new
Row
(
children:
<
Widget
>[
new
Wrapper
(
child:
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
Wrapper
(
child:
new
SizedBox
(
key:
victimKey
)
);
})
),
new
Wrapper
(
child:
new
Wrapper
(
child:
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
SizedBox
();
})
)
),
]));
});
}
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