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,
|
Key key,
|
||||||
this.mainAxis: Axis.vertical,
|
this.mainAxis: Axis.vertical,
|
||||||
this.elevation: 2,
|
this.elevation: 2,
|
||||||
|
this.hasDividers: false,
|
||||||
this.children: const <MergeableMaterialItem>[]
|
this.children: const <MergeableMaterialItem>[]
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -94,6 +95,9 @@ class MergeableMaterial extends StatefulWidget {
|
|||||||
/// The elevation of all the [Material] slices.
|
/// The elevation of all the [Material] slices.
|
||||||
final int elevation;
|
final int elevation;
|
||||||
|
|
||||||
|
/// Whether connected pieces of [MaterialSlice] have dividers between them.
|
||||||
|
final bool hasDividers;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'MergeableMaterial('
|
return 'MergeableMaterial('
|
||||||
@ -234,6 +238,21 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
|||||||
return false;
|
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
|
@override
|
||||||
void didUpdateConfig(MergeableMaterial oldConfig) {
|
void didUpdateConfig(MergeableMaterial oldConfig) {
|
||||||
super.didUpdateConfig(oldConfig);
|
super.didUpdateConfig(oldConfig);
|
||||||
@ -253,17 +272,7 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
|||||||
|
|
||||||
assert(_debugGapsAreValid(newChildren));
|
assert(_debugGapsAreValid(newChildren));
|
||||||
|
|
||||||
while (j < _children.length) {
|
_removeEmptyGaps();
|
||||||
if (_children[j] is MaterialGap &&
|
|
||||||
_animationTuples[_children[j].key].controller.status
|
|
||||||
== AnimationStatus.dismissed) {
|
|
||||||
_removeChild(j);
|
|
||||||
} else {
|
|
||||||
j += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
|
|
||||||
while (i < newChildren.length && j < _children.length) {
|
while (i < newChildren.length && j < _children.length) {
|
||||||
if (newOnly.contains(newChildren[i].key) ||
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
_removeEmptyGaps();
|
||||||
|
|
||||||
final List<Widget> widgets = <Widget>[];
|
final List<Widget> widgets = <Widget>[];
|
||||||
List<Widget> slices = <Widget>[];
|
List<Widget> slices = <Widget>[];
|
||||||
|
List<Key> keys = <Key>[];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < _children.length; i += 1) {
|
for (i = 0; i < _children.length; i += 1) {
|
||||||
@ -489,11 +525,12 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
|||||||
),
|
),
|
||||||
child: new BlockBody(
|
child: new BlockBody(
|
||||||
mainAxis: config.mainAxis,
|
mainAxis: config.mainAxis,
|
||||||
children: slices
|
children: _divideSlices(context, slices, keys)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
slices = <Widget>[];
|
slices = <Widget>[];
|
||||||
|
keys = <Key>[];
|
||||||
|
|
||||||
widgets.add(
|
widgets.add(
|
||||||
new SizedBox(
|
new SizedBox(
|
||||||
@ -506,14 +543,11 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
|||||||
|
|
||||||
slices.add(
|
slices.add(
|
||||||
new Material(
|
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,
|
type: MaterialType.transparency,
|
||||||
child: slice.child
|
child: slice.child
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
keys.add(new _MergeableMaterialSliceKey(_children[i].key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,11 +561,12 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
|
|||||||
),
|
),
|
||||||
child: new BlockBody(
|
child: new BlockBody(
|
||||||
mainAxis: config.mainAxis,
|
mainAxis: config.mainAxis,
|
||||||
children: slices
|
children: _divideSlices(context, slices, keys)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
slices = <Widget>[];
|
slices = <Widget>[];
|
||||||
|
keys = <Key>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new _MergeableMaterialBlockBody(
|
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 {
|
class _MergeableMaterialSliceKey extends GlobalKey {
|
||||||
const _MergeableMaterialSliceKey(this.value) : super.constructor();
|
const _MergeableMaterialSliceKey(this.value) : super.constructor();
|
||||||
|
|
||||||
@ -558,6 +595,11 @@ class _MergeableMaterialSliceKey extends GlobalKey {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => value.hashCode;
|
int get hashCode => value.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '_MergeableMaterialSliceKey($value)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MergeableMaterialBlockBody extends BlockBody {
|
class _MergeableMaterialBlockBody extends BlockBody {
|
||||||
|
@ -1014,4 +1014,116 @@ void main() {
|
|||||||
matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
|
matches(getBorderRadius(tester, 0), RadiusType.Round, RadiusType.Round);
|
||||||
matches(getBorderRadius(tester, 1), 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