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
27a73a58
Commit
27a73a58
authored
Jan 27, 2016
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1400 from abarth/reorder_update_children
updateChildren() needs to walk the list forward
parents
5cfccb91
05839e51
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
118 additions
and
118 deletions
+118
-118
object.dart
packages/flutter/lib/src/rendering/object.dart
+37
-34
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+61
-56
homogeneous_viewport.dart
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
+2
-4
mixed_viewport.dart
packages/flutter/lib/src/widgets/mixed_viewport.dart
+11
-14
virtual_viewport.dart
packages/flutter/lib/src/widgets/virtual_viewport.dart
+2
-4
focus_test.dart
packages/flutter/test/widget/focus_test.dart
+5
-6
No files found.
packages/flutter/lib/src/rendering/object.dart
View file @
27a73a58
...
...
@@ -1294,59 +1294,62 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
ChildType
_firstChild
;
ChildType
_lastChild
;
void
_
addToChildList
(
ChildType
child
,
{
ChildType
before
})
{
void
_
insertIntoChildList
(
ChildType
child
,
{
ChildType
after
})
{
final
ParentDataType
childParentData
=
child
.
parentData
;
assert
(
childParentData
.
nextSibling
==
null
);
assert
(
childParentData
.
previousSibling
==
null
);
_childCount
+=
1
;
assert
(
_childCount
>
0
);
if
(
before
==
null
)
{
//
append at the end (_la
stChild)
childParentData
.
previousSibling
=
_la
stChild
;
if
(
_
la
stChild
!=
null
)
{
final
ParentDataType
_
lastChildParentData
=
_la
stChild
.
parentData
;
_
lastChildParentData
.
next
Sibling
=
child
;
if
(
after
==
null
)
{
//
insert at the start (_fir
stChild)
childParentData
.
nextSibling
=
_fir
stChild
;
if
(
_
fir
stChild
!=
null
)
{
final
ParentDataType
_
firstChildParentData
=
_fir
stChild
.
parentData
;
_
firstChildParentData
.
previous
Sibling
=
child
;
}
_
la
stChild
=
child
;
if
(
_
fir
stChild
==
null
)
_
fir
stChild
=
child
;
_
fir
stChild
=
child
;
if
(
_
la
stChild
==
null
)
_
la
stChild
=
child
;
}
else
{
assert
(
_firstChild
!=
null
);
assert
(
_lastChild
!=
null
);
assert
(
_debugUltimatePreviousSiblingOf
(
before
,
equals:
_firstChild
));
assert
(
_debugUltimateNextSiblingOf
(
before
,
equals:
_lastChild
));
final
ParentDataType
beforeParentData
=
before
.
parentData
;
if
(
beforeParentData
.
previous
Sibling
==
null
)
{
// insert at the
start (_fir
stChild); we'll end up with two or more children
assert
(
before
==
_fir
stChild
);
childParentData
.
nextSibling
=
before
;
beforeParentData
.
previous
Sibling
=
child
;
_
fir
stChild
=
child
;
assert
(
_debugUltimatePreviousSiblingOf
(
after
,
equals:
_firstChild
));
assert
(
_debugUltimateNextSiblingOf
(
after
,
equals:
_lastChild
));
final
ParentDataType
afterParentData
=
after
.
parentData
;
if
(
afterParentData
.
next
Sibling
==
null
)
{
// insert at the
end (_la
stChild); we'll end up with two or more children
assert
(
after
==
_la
stChild
);
childParentData
.
previousSibling
=
after
;
afterParentData
.
next
Sibling
=
child
;
_
la
stChild
=
child
;
}
else
{
// insert in the middle; we'll end up with three or more children
// set up links from child to siblings
childParentData
.
previousSibling
=
beforeParentData
.
previous
Sibling
;
childParentData
.
nextSibling
=
before
;
childParentData
.
nextSibling
=
afterParentData
.
next
Sibling
;
childParentData
.
previousSibling
=
after
;
// set up links from siblings to child
final
ParentDataType
childPreviousSiblingParentData
=
childParentData
.
previousSibling
.
parentData
;
final
ParentDataType
childNextSiblingParentData
=
childParentData
.
nextSibling
.
parentData
;
childPreviousSiblingParentData
.
nextSibling
=
child
;
childNextSiblingParentData
.
previousSibling
=
child
;
assert
(
beforeParentData
.
previous
Sibling
==
child
);
assert
(
afterParentData
.
next
Sibling
==
child
);
}
}
}
/// Insert child into this render object's child list before the given child.
///
/// To insert a child at the end of the child list, omit the before parameter.
void
add
(
ChildType
child
,
{
ChildType
before
})
{
/// Insert child into this render object's child list after the given child.
void
insert
(
ChildType
child
,
{
ChildType
after
})
{
assert
(
child
!=
this
);
assert
(
before
!=
this
);
assert
(
child
!=
before
);
assert
(
after
!=
this
);
assert
(
child
!=
after
);
assert
(
child
!=
_firstChild
);
assert
(
child
!=
_lastChild
);
adoptChild
(
child
);
_addToChildList
(
child
,
before:
before
);
_insertIntoChildList
(
child
,
after:
after
);
}
/// Append child to the end of this render object's child list.
void
add
(
ChildType
child
)
{
insert
(
child
,
after:
_lastChild
);
}
/// Add all the children to the end of this render object's child list.
...
...
@@ -1411,16 +1414,16 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
/// More efficient than removing and re-adding the child. Requires the child
/// to already be in the child list at some position. Pass null for before to
/// move the child to the end of the child list.
void
move
(
ChildType
child
,
{
ChildType
before
})
{
void
move
(
ChildType
child
,
{
ChildType
after
})
{
assert
(
child
!=
this
);
assert
(
before
!=
this
);
assert
(
child
!=
before
);
assert
(
after
!=
this
);
assert
(
child
!=
after
);
assert
(
child
.
parent
==
this
);
final
ParentDataType
childParentData
=
child
.
parentData
;
if
(
childParentData
.
nextSibling
==
before
)
if
(
childParentData
.
previousSibling
==
after
)
return
;
_removeFromChildList
(
child
);
_
addToChildList
(
child
,
before:
before
);
_
insertIntoChildList
(
child
,
after:
after
);
}
void
attach
()
{
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
27a73a58
...
...
@@ -1507,79 +1507,80 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Buildab
// Widgets without keys might be synced but there is no guarantee.
// The general approach is to sync the entire new list backwards, as follows:
// 1. Walk the lists from the top until you no longer have
// matching nodes. We don't sync these yet, but we now know to
// skip them below. We do this because at each sync we need to
// pass the pointer to the new next widget as the slot, which
// we can't do until we've synced the next child.
// 2. Walk the lists from the bottom, syncing nodes, until you no
// longer have matching nodes.
// 1. Walk the lists from the top, syncing nodes, until you no longer have
// matching nodes.
// 2. Walk the lists from the bottom, without syncing nodes, until you no
// longer have matching nodes. We'll sync these nodes at the end. We
// don't sync them now because we want to sync all the nodes in order
// from beginning ot end.
// At this point we narrowed the old and new lists to the point
// where the nodes no longer match.
// 3. Walk the narrowed part of the old list to get the list of
// keys and sync null with non-keyed items.
// 4. Walk the narrowed part of the new list
back
wards:
// 4. Walk the narrowed part of the new list
for
wards:
// * Sync unkeyed items with null
// * Sync keyed items with the source if it exists, else with null.
// 5. Walk the
top list again but backwards
, syncing the nodes.
// 5. Walk the
bottom of the list again
, syncing the nodes.
// 6. Sync null with any items in the list of keys that are still
// mounted.
int
childrenTop
=
0
;
int
newChildrenTop
=
0
;
int
oldChildrenTop
=
0
;
int
newChildrenBottom
=
newWidgets
.
length
-
1
;
int
oldChildrenBottom
=
oldChildren
.
length
-
1
;
// top of the lists
while
((
childrenTop
<=
oldChildrenBottom
)
&&
(
childrenTop
<=
newChildrenBottom
))
{
Element
oldChild
=
oldChildren
[
childrenTop
];
Widget
newWidget
=
newWidgets
[
childrenTop
];
List
<
Element
>
newChildren
=
oldChildren
.
length
==
newWidgets
.
length
?
oldChildren
:
new
List
<
Element
>(
newWidgets
.
length
);
Element
previousChild
;
// Update the top of the list.
while
((
oldChildrenTop
<=
oldChildrenBottom
)
&&
(
newChildrenTop
<=
newChildrenBottom
))
{
Element
oldChild
=
oldChildren
[
oldChildrenTop
];
Widget
newWidget
=
newWidgets
[
newChildrenTop
];
assert
(
oldChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
if
(!
Widget
.
canUpdate
(
oldChild
.
widget
,
newWidget
))
break
;
childrenTop
+=
1
;
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
previousChild
);
assert
(
newChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
newChildren
[
newChildrenTop
]
=
newChild
;
previousChild
=
newChild
;
newChildrenTop
+=
1
;
oldChildrenTop
+=
1
;
}
List
<
Element
>
newChildren
=
oldChildren
.
length
==
newWidgets
.
length
?
oldChildren
:
new
List
<
Element
>(
newWidgets
.
length
);
Element
nextSibling
;
// bottom of the lists
while
((
childrenTop
<=
oldChildrenBottom
)
&&
(
childrenTop
<=
newChildrenBottom
))
{
// Scan the bottom of the list.
while
((
oldChildrenTop
<=
oldChildrenBottom
)
&&
(
newChildrenTop
<=
newChildrenBottom
))
{
Element
oldChild
=
oldChildren
[
oldChildrenBottom
];
Widget
newWidget
=
newWidgets
[
newChildrenBottom
];
assert
(
oldChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
if
(!
Widget
.
canUpdate
(
oldChild
.
widget
,
newWidget
))
break
;
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
nextSibling
);
assert
(
newChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
newChildren
[
newChildrenBottom
]
=
newChild
;
nextSibling
=
newChild
;
oldChildrenBottom
-=
1
;
newChildrenBottom
-=
1
;
}
//
middle of the lists - old list
bool
haveOld
Nodes
=
c
hildrenTop
<=
oldChildrenBottom
;
//
Scan the old children in the middle of the list.
bool
haveOld
Children
=
oldC
hildrenTop
<=
oldChildrenBottom
;
Map
<
Key
,
Element
>
oldKeyedChildren
;
if
(
haveOld
Nodes
)
{
if
(
haveOld
Children
)
{
oldKeyedChildren
=
new
Map
<
Key
,
Element
>();
while
(
c
hildrenTop
<=
oldChildrenBottom
)
{
Element
oldChild
=
oldChildren
[
oldChildren
Bottom
];
while
(
oldC
hildrenTop
<=
oldChildrenBottom
)
{
Element
oldChild
=
oldChildren
[
oldChildren
Top
];
assert
(
oldChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
if
(
oldChild
.
widget
.
key
!=
null
)
oldKeyedChildren
[
oldChild
.
widget
.
key
]
=
oldChild
;
else
_deactivateChild
(
oldChild
);
oldChildren
Bottom
-
=
1
;
oldChildren
Top
+
=
1
;
}
}
//
middle of the lists - new list
while
(
c
hildrenTop
<=
newChildrenBottom
)
{
//
Update the middle of the list.
while
(
newC
hildrenTop
<=
newChildrenBottom
)
{
Element
oldChild
;
Widget
newWidget
=
newWidgets
[
newChildren
Bottom
];
if
(
haveOld
Nodes
)
{
Widget
newWidget
=
newWidgets
[
newChildren
Top
];
if
(
haveOld
Children
)
{
Key
key
=
newWidget
.
key
;
if
(
key
!=
null
)
{
oldChild
=
oldKeyedChildren
[
newWidget
.
key
];
...
...
@@ -1596,32 +1597,38 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Buildab
}
}
assert
(
oldChild
==
null
||
Widget
.
canUpdate
(
oldChild
.
widget
,
newWidget
));
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
nextSibling
);
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
previousChild
);
assert
(
newChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
assert
(
oldChild
==
newChild
||
oldChild
==
null
||
oldChild
.
_debugLifecycleState
!=
_ElementLifecycle
.
active
);
newChildren
[
newChildren
Bottom
]
=
newChild
;
nextSibling
=
newChild
;
newChildren
Bottom
-
=
1
;
newChildren
[
newChildren
Top
]
=
newChild
;
previousChild
=
newChild
;
newChildren
Top
+
=
1
;
}
assert
(
oldChildrenBottom
==
newChildrenBottom
);
assert
(
childrenTop
==
newChildrenBottom
+
1
);
// now sync the top of the list
while
(
childrenTop
>
0
)
{
childrenTop
-=
1
;
Element
oldChild
=
oldChildren
[
childrenTop
];
// We've scaned the whole list.
assert
(
oldChildrenTop
==
oldChildrenBottom
+
1
);
assert
(
newChildrenTop
==
newChildrenBottom
+
1
);
assert
(
newWidgets
.
length
-
newChildrenTop
==
oldChildren
.
length
-
oldChildrenTop
);
newChildrenBottom
=
newWidgets
.
length
-
1
;
oldChildrenBottom
=
oldChildren
.
length
-
1
;
// Update the bottom of the list.
while
((
oldChildrenTop
<=
oldChildrenBottom
)
&&
(
newChildrenTop
<=
newChildrenBottom
))
{
Element
oldChild
=
oldChildren
[
oldChildrenTop
];
assert
(
oldChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
Widget
newWidget
=
newWidgets
[
c
hildrenTop
];
Widget
newWidget
=
newWidgets
[
newC
hildrenTop
];
assert
(
Widget
.
canUpdate
(
oldChild
.
widget
,
newWidget
));
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
nextSibling
);
Element
newChild
=
updateChild
(
oldChild
,
newWidget
,
previousChild
);
assert
(
newChild
.
_debugLifecycleState
==
_ElementLifecycle
.
active
);
assert
(
oldChild
==
newChild
||
oldChild
==
null
||
oldChild
.
_debugLifecycleState
!=
_ElementLifecycle
.
active
);
newChildren
[
childrenTop
]
=
newChild
;
nextSibling
=
newChild
;
newChildren
[
newChildrenTop
]
=
newChild
;
previousChild
=
newChild
;
newChildrenTop
+=
1
;
oldChildrenTop
+=
1
;
}
// clean up any of the remaining middle nodes from the old list
if
(
haveOld
Nodes
&&
!
oldKeyedChildren
.
isEmpty
)
{
if
(
haveOld
Children
&&
!
oldKeyedChildren
.
isEmpty
)
{
for
(
Element
oldChild
in
oldKeyedChildren
.
values
)
_deactivateChild
(
oldChild
);
}
...
...
@@ -1755,15 +1762,13 @@ class MultiChildRenderObjectElement<T extends MultiChildRenderObjectWidget> exte
void
insertChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
final
ContainerRenderObjectMixin
renderObject
=
this
.
renderObject
;
final
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
add
(
child
,
before:
nextSibling
);
renderObject
.
insert
(
child
,
after:
slot
?.
renderObject
);
assert
(
renderObject
==
this
.
renderObject
);
}
void
moveChildRenderObject
(
RenderObject
child
,
dynamic
slot
)
{
final
ContainerRenderObjectMixin
renderObject
=
this
.
renderObject
;
final
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
move
(
child
,
before:
nextSibling
);
renderObject
.
move
(
child
,
after:
slot
?.
renderObject
);
assert
(
renderObject
==
this
.
renderObject
);
}
...
...
@@ -1797,7 +1802,7 @@ class MultiChildRenderObjectElement<T extends MultiChildRenderObjectWidget> exte
super
.
mount
(
parent
,
newSlot
);
_children
=
new
List
<
Element
>(
widget
.
children
.
length
);
Element
previousChild
;
for
(
int
i
=
_children
.
length
-
1
;
i
>=
0
;
--
i
)
{
for
(
int
i
=
0
;
i
<
_children
.
length
;
++
i
)
{
Element
newChild
=
_inflateWidget
(
widget
.
children
[
i
],
previousChild
);
_children
[
i
]
=
newChild
;
previousChild
=
newChild
;
...
...
packages/flutter/lib/src/widgets/homogeneous_viewport.dart
View file @
27a73a58
...
...
@@ -118,14 +118,12 @@ abstract class _ViewportBaseElement<T extends _ViewportBase> extends RenderObjec
}
void
insertChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
add
(
child
,
before:
nextSibling
);
renderObject
.
insert
(
child
,
after:
slot
?.
renderObject
);
}
void
moveChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
assert
(
child
.
parent
==
renderObject
);
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
move
(
child
,
before:
nextSibling
);
renderObject
.
move
(
child
,
after:
slot
?.
renderObject
);
}
void
removeChildRenderObject
(
RenderObject
child
)
{
...
...
packages/flutter/lib/src/widgets/mixed_viewport.dart
View file @
27a73a58
...
...
@@ -552,14 +552,12 @@ class _MixedViewportElement extends RenderObjectElement<MixedViewport> {
if
(
haveChildren
)
{
// Place all our children in our RenderObject.
// All the children we are placing are in builtChildren and newChildren.
// We will walk them backwards so we can set the slots at the same time.
Element
nextSibling
=
null
;
while
(
index
>
startIndex
)
{
index
-=
1
;
final
Element
element
=
builtChildren
[
index
];
if
(
element
.
slot
!=
nextSibling
)
updateSlotForChild
(
element
,
nextSibling
);
nextSibling
=
element
;
Element
previousChild
=
null
;
for
(
int
i
=
startIndex
;
i
<
index
;
++
i
)
{
final
Element
element
=
builtChildren
[
i
];
if
(
element
.
slot
!=
previousChild
)
updateSlotForChild
(
element
,
previousChild
);
previousChild
=
element
;
}
}
...
...
@@ -577,20 +575,19 @@ class _MixedViewportElement extends RenderObjectElement<MixedViewport> {
if
(
slot
==
_omit
)
return
;
assert
(
slot
==
null
||
slot
is
Element
);
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
add
(
child
,
before:
nextSibling
);
renderObject
.
insert
(
child
,
after:
slot
?.
renderObject
);
}
void
moveChildRenderObject
(
RenderObject
child
,
dynamic
slot
)
{
if
(
slot
==
_omit
)
return
;
assert
(
slot
==
null
||
slot
is
Element
);
RenderObject
next
Sibling
=
slot
?.
renderObject
;
assert
(
nextSibling
==
null
||
next
Sibling
.
parent
==
renderObject
);
RenderObject
previous
Sibling
=
slot
?.
renderObject
;
assert
(
previousSibling
==
null
||
previous
Sibling
.
parent
==
renderObject
);
if
(
child
.
parent
==
renderObject
)
renderObject
.
move
(
child
,
before:
next
Sibling
);
renderObject
.
move
(
child
,
after:
previous
Sibling
);
else
renderObject
.
add
(
child
,
before:
next
Sibling
);
renderObject
.
insert
(
child
,
after:
previous
Sibling
);
}
void
removeChildRenderObject
(
RenderObject
child
)
{
...
...
packages/flutter/lib/src/widgets/virtual_viewport.dart
View file @
27a73a58
...
...
@@ -149,14 +149,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
}
void
insertChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
add
(
child
,
before:
nextSibling
);
renderObject
.
insert
(
child
,
after:
slot
?.
renderObject
);
}
void
moveChildRenderObject
(
RenderObject
child
,
Element
slot
)
{
assert
(
child
.
parent
==
renderObject
);
RenderObject
nextSibling
=
slot
?.
renderObject
;
renderObject
.
move
(
child
,
before:
nextSibling
);
renderObject
.
move
(
child
,
after:
slot
?.
renderObject
);
}
void
removeChildRenderObject
(
RenderObject
child
)
{
...
...
packages/flutter/test/widget/focus_test.dart
View file @
27a73a58
...
...
@@ -38,17 +38,16 @@ void main() {
key:
keyFocus
,
child:
new
Column
(
children:
<
Widget
>[
// reverse these when you fix https://github.com/flutter/engine/issues/1495
new
TestFocusable
(
key:
keyB
,
no:
'b'
,
yes:
'B FOCUSED'
),
new
TestFocusable
(
key:
keyA
,
no:
'a'
,
yes:
'A FOCUSED'
),
new
TestFocusable
(
key:
keyB
,
no:
'b'
,
yes:
'B FOCUSED'
),
]
)
)
...
...
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