Merge pull request #2846 from HansMuller/two_level_list
TwoLevelList fails to restore sublist expanded state
This commit is contained in:
@@ -154,11 +154,14 @@ class _TwoLevelSublistState extends State<TwoLevelSublist> {
|
||||
}
|
||||
|
||||
class TwoLevelList extends StatelessWidget {
|
||||
TwoLevelList({ Key key, this.items, this.type: MaterialListType.twoLine }) : super(key: key);
|
||||
TwoLevelList({ Key key, this.scrollableKey, this.items, this.type: MaterialListType.twoLine }) : super(key: key);
|
||||
|
||||
final List<Widget> items;
|
||||
final MaterialListType type;
|
||||
final Key scrollableKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => new Block(children: items);
|
||||
Widget build(BuildContext context) {
|
||||
return new Block(children: KeyedSubtree.ensureUniqueKeysForList(items), scrollableKey: scrollableKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'dart:ui' as ui show Image;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'debug.dart';
|
||||
import 'framework.dart';
|
||||
|
||||
export 'package:flutter/animation.dart';
|
||||
@@ -2575,6 +2576,27 @@ class KeyedSubtree extends StatelessWidget {
|
||||
/// The widget below this widget in the tree.
|
||||
final Widget child;
|
||||
|
||||
/// Wrap each item in a KeyedSubtree whose key is based on the item's existing key or
|
||||
/// its list index + baseIndex.
|
||||
static List<Widget> ensureUniqueKeysForList(Iterable<Widget> items, { int baseIndex: 0 }) {
|
||||
if (items == null || items.isEmpty)
|
||||
return items;
|
||||
|
||||
List<Widget> itemsWithUniqueKeys = <Widget>[];
|
||||
int itemIndex = baseIndex;
|
||||
for(Widget item in items) {
|
||||
itemsWithUniqueKeys.add(new KeyedSubtree(
|
||||
key: item.key != null ? new ValueKey<Key>(item.key) : new ValueKey<int>(itemIndex),
|
||||
child: item
|
||||
));
|
||||
itemIndex += 1;
|
||||
}
|
||||
|
||||
assert(!debugItemsHaveDuplicateKeys(itemsWithUniqueKeys));
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => child;
|
||||
}
|
||||
|
||||
@@ -25,22 +25,39 @@ bool debugCheckHasMediaQuery(BuildContext context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool debugHasDuplicateKeys(Widget parent, Iterable<Widget> children) {
|
||||
Key _firstNonUniqueKey(Iterable<Widget> widgets) {
|
||||
Set<Key> keySet = new HashSet<Key>();
|
||||
for (Widget widget in widgets) {
|
||||
assert(widget != null);
|
||||
if (widget.key == null)
|
||||
continue;
|
||||
if (!keySet.add(widget.key))
|
||||
return widget.key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool debugChildrenHaveDuplicateKeys(Widget parent, Iterable<Widget> children) {
|
||||
assert(() {
|
||||
Set<Key> keySet = new HashSet<Key>();
|
||||
for (Widget child in children) {
|
||||
assert(child != null);
|
||||
if (child.key == null)
|
||||
continue;
|
||||
if (!keySet.add(child.key)) {
|
||||
throw new FlutterError(
|
||||
'Duplicate keys found.\n'
|
||||
'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
|
||||
'$parent has multiple children with key "${child.key}".'
|
||||
);
|
||||
}
|
||||
final Key nonUniqueKey = _firstNonUniqueKey(children);
|
||||
if (nonUniqueKey != null) {
|
||||
throw new FlutterError(
|
||||
'Duplicate keys found.\n'
|
||||
'If multiple keyed nodes exist as children of another node, they must have unique keys.\n'
|
||||
'$parent has multiple children with key $nonUniqueKey.'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
bool debugItemsHaveDuplicateKeys(Iterable<Widget> items) {
|
||||
assert(() {
|
||||
final Key nonUniqueKey = _firstNonUniqueKey(items);
|
||||
if (nonUniqueKey != null)
|
||||
throw new FlutterError('Duplicate key found: $nonUniqueKey.\n');
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1937,7 +1937,7 @@ class SingleChildRenderObjectElement extends RenderObjectElement {
|
||||
/// Instantiation of RenderObjectWidgets that can have a list of children
|
||||
class MultiChildRenderObjectElement extends RenderObjectElement {
|
||||
MultiChildRenderObjectElement(MultiChildRenderObjectWidget widget) : super(widget) {
|
||||
assert(!debugHasDuplicateKeys(widget, widget.children));
|
||||
assert(!debugChildrenHaveDuplicateKeys(widget, widget.children));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -173,8 +173,9 @@ abstract class VirtualViewportElement extends RenderObjectElement {
|
||||
Key key = child.key != null ? new ValueKey<Key>(child.key) : new ValueKey<int>(childIndex);
|
||||
newWidgets[i] = new RepaintBoundary(key: key, child: child);
|
||||
}
|
||||
assert(!debugHasDuplicateKeys(widget, newWidgets));
|
||||
_materializedChildren = updateChildren(_materializedChildren, newWidgets);
|
||||
|
||||
assert(!debugChildrenHaveDuplicateKeys(widget, newWidgets));
|
||||
_materializedChildren = updateChildren(_materializedChildren, newWidgets.toList());
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user