Added a flag to divide Material slices. (#5402)
This commit changes MergeableMaterial to include a flag that specifies whether connected Material slices should have dividers between them.
This commit is contained in:
parent
a010d6eb08
commit
508b8c460c
@ -82,6 +82,7 @@ class MergeableMaterial extends StatefulWidget {
|
||||
Key key,
|
||||
this.mainAxis: Axis.vertical,
|
||||
this.elevation: 2,
|
||||
this.hasDividers: false,
|
||||
this.children: const <MergeableMaterialItem>[]
|
||||
}) : super(key: key);
|
||||
|
||||
@ -94,6 +95,9 @@ class MergeableMaterial extends StatefulWidget {
|
||||
/// The elevation of all the [Material] slices.
|
||||
final int elevation;
|
||||
|
||||
/// Whether connected pieces of [MaterialSlice] have dividers between them.
|
||||
final bool hasDividers;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MergeableMaterial('
|
||||
@ -234,6 +238,21 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
return false;
|
||||
}
|
||||
|
||||
void _removeEmptyGaps() {
|
||||
int j = 0;
|
||||
|
||||
while (j < _children.length) {
|
||||
if (
|
||||
_children[j] is MaterialGap &&
|
||||
_animationTuples[_children[j].key].controller.status == AnimationStatus.dismissed
|
||||
) {
|
||||
_removeChild(j);
|
||||
} else {
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateConfig(MergeableMaterial oldConfig) {
|
||||
super.didUpdateConfig(oldConfig);
|
||||
@ -253,17 +272,7 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
|
||||
assert(_debugGapsAreValid(newChildren));
|
||||
|
||||
while (j < _children.length) {
|
||||
if (_children[j] is MaterialGap &&
|
||||
_animationTuples[_children[j].key].controller.status
|
||||
== AnimationStatus.dismissed) {
|
||||
_removeChild(j);
|
||||
} else {
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
j = 0;
|
||||
_removeEmptyGaps();
|
||||
|
||||
while (i < newChildren.length && j < _children.length) {
|
||||
if (newOnly.contains(newChildren[i].key) ||
|
||||
@ -471,10 +480,37 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _divideSlices(BuildContext context, List<Widget> slices, List<Key> keys) {
|
||||
if (config.hasDividers) {
|
||||
List<Widget> divided = <Widget>[];
|
||||
|
||||
for (int i = 0; i < slices.length; i += 1) {
|
||||
divided.add(
|
||||
new DecoratedBox(
|
||||
key: keys[i],
|
||||
decoration: i != slices.length - 1 ? new BoxDecoration(
|
||||
border: new Border(
|
||||
bottom: new BorderSide(color: Theme.of(context).dividerColor)
|
||||
)
|
||||
) : new BoxDecoration(),
|
||||
child: slices[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return divided;
|
||||
} else {
|
||||
return slices;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_removeEmptyGaps();
|
||||
|
||||
final List<Widget> widgets = <Widget>[];
|
||||
List<Widget> slices = <Widget>[];
|
||||
List<Key> keys = <Key>[];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _children.length; i += 1) {
|
||||
@ -489,11 +525,12 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
),
|
||||
child: new BlockBody(
|
||||
mainAxis: config.mainAxis,
|
||||
children: slices
|
||||
children: _divideSlices(context, slices, keys)
|
||||
)
|
||||
)
|
||||
);
|
||||
slices = <Widget>[];
|
||||
keys = <Key>[];
|
||||
|
||||
widgets.add(
|
||||
new SizedBox(
|
||||
@ -506,14 +543,11 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
|
||||
slices.add(
|
||||
new Material(
|
||||
// Since slices live in different Material widgets, the parent
|
||||
// hierarchy can change and lead to the slice being rebuilt. Using
|
||||
// a global key solves the issue.
|
||||
key: new _MergeableMaterialSliceKey(_children[i].key),
|
||||
type: MaterialType.transparency,
|
||||
child: slice.child
|
||||
)
|
||||
);
|
||||
keys.add(new _MergeableMaterialSliceKey(_children[i].key));
|
||||
}
|
||||
}
|
||||
|
||||
@ -527,11 +561,12 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
),
|
||||
child: new BlockBody(
|
||||
mainAxis: config.mainAxis,
|
||||
children: slices
|
||||
children: _divideSlices(context, slices, keys)
|
||||
)
|
||||
)
|
||||
);
|
||||
slices = <Widget>[];
|
||||
keys = <Key>[];
|
||||
}
|
||||
|
||||
return new _MergeableMaterialBlockBody(
|
||||
@ -543,6 +578,8 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
||||
}
|
||||
}
|
||||
|
||||
// The parent hierarchy can change and lead to the slice being
|
||||
// rebuilt. Usinga global key solves the issue.
|
||||
class _MergeableMaterialSliceKey extends GlobalKey {
|
||||
const _MergeableMaterialSliceKey(this.value) : super.constructor();
|
||||
|
||||
@ -558,6 +595,11 @@ class _MergeableMaterialSliceKey extends GlobalKey {
|
||||
|
||||
@override
|
||||
int get hashCode => value.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '_MergeableMaterialSliceKey($value)';
|
||||
}
|
||||
}
|
||||
|
||||
class _MergeableMaterialBlockBody extends BlockBody {
|
||||
|
@ -1014,4 +1014,116 @@ void main() {
|
||||
matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
|
||||
matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
|
||||
});
|
||||
|
||||
bool isDivider(Widget widget) {
|
||||
final DecoratedBox box = widget;
|
||||
|
||||
return box.decoration == new BoxDecoration(
|
||||
border: new Border(
|
||||
bottom: new BorderSide(color: const Color(0x1F000000))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('MergeableMaterial dividers', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new Scaffold(
|
||||
body: new ScrollableViewport(
|
||||
child: new MergeableMaterial(
|
||||
hasDividers: true,
|
||||
children: <MergeableMaterialItem>[
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('A'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('B'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('C'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('D'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Widget> boxes = tester.widgetList(find.byType(DecoratedBox)).toList();
|
||||
int offset = 3;
|
||||
|
||||
expect(isDivider(boxes[offset]), isTrue);
|
||||
expect(isDivider(boxes[offset + 1]), isTrue);
|
||||
expect(isDivider(boxes[offset + 2]), isTrue);
|
||||
expect(isDivider(boxes[offset + 3]), isFalse);
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Scaffold(
|
||||
body: new ScrollableViewport(
|
||||
child: new MergeableMaterial(
|
||||
hasDividers: true,
|
||||
children: <MergeableMaterialItem>[
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('A'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('B'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialGap(
|
||||
key: new ValueKey<String>('x')
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('C'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
),
|
||||
new MaterialSlice(
|
||||
key: new ValueKey<String>('D'),
|
||||
child: new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
boxes = tester.widgetList(find.byType(DecoratedBox)).toList();
|
||||
offset = 3;
|
||||
|
||||
expect(isDivider(boxes[offset]), isTrue);
|
||||
expect(isDivider(boxes[offset + 1]), isFalse);
|
||||
// offset + 2 is gap
|
||||
expect(isDivider(boxes[offset + 3]), isTrue);
|
||||
expect(isDivider(boxes[offset + 4]), isFalse);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user