Commit 826d87a9 authored by Dragoș Tiselice's avatar Dragoș Tiselice Committed by GitHub

Made MergeableMaterial dividers animated seamlessly. (#5857)

Changed MergableMaterial to animated between states that have dividers
and those that don't in order not to have dividers that appear
unanimatedly. Fixes #5847.
parent f4904b14
......@@ -228,7 +228,7 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
_animationTuples[child.key] = null;
}
bool _closingGap(int index) {
bool _isClosingGap(int index) {
if (index < _children.length - 1 && _children[index] is MaterialGap) {
return _animationTuples[_children[index].key].controller.status ==
AnimationStatus.reverse;
......@@ -284,7 +284,7 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
i += 1;
// Skip old keys.
while (oldOnly.contains(_children[j].key) || _closingGap(j))
while (oldOnly.contains(_children[j].key) || _isClosingGap(j))
j += 1;
final int newLength = i - startNew;
......@@ -479,28 +479,12 @@ 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;
}
bool _willNeedDivider(int index) {
if (index < 0)
return false;
if (index >= _children.length)
return false;
return _children[index] is MaterialSlice || _isClosingGap(index);
}
@override
......@@ -509,7 +493,6 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
final List<Widget> widgets = <Widget>[];
List<Widget> slices = <Widget>[];
List<Key> keys = <Key>[];
int i;
for (i = 0; i < _children.length; i += 1) {
......@@ -524,12 +507,11 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
),
child: new BlockBody(
mainAxis: config.mainAxis,
children: _divideSlices(context, slices, keys)
children: slices
)
)
);
slices = <Widget>[];
keys = <Key>[];
widgets.add(
new SizedBox(
......@@ -539,14 +521,50 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
);
} else {
MaterialSlice slice = _children[i];
Widget child = slice.child;
if (config.hasDividers) {
final bool hasTopDivider = _willNeedDivider(i - 1);
final bool hasBottomDivider = _willNeedDivider(i + 1);
Border border;
final BorderSide divider = new BorderSide(
color: Theme.of(context).dividerColor,
width: 0.5
);
if (i == 0) {
border = new Border(
bottom: hasBottomDivider ? divider : BorderSide.none
);
} else if (i == _children.length - 1) {
border = new Border(
top: hasTopDivider ? divider : BorderSide.none
);
} else {
border = new Border(
top: hasTopDivider ? divider : BorderSide.none,
bottom: hasBottomDivider ? divider : BorderSide.none
);
}
assert(border != null);
child = new AnimatedContainer(
key: new _MergeableMaterialSliceKey(_children[i].key),
decoration: new BoxDecoration(border: border),
duration: kThemeAnimationDuration,
curve: Curves.fastOutSlowIn,
child: child
);
}
slices.add(
new Material(
type: MaterialType.transparency,
child: slice.child
child: child
)
);
keys.add(new _MergeableMaterialSliceKey(_children[i].key));
}
}
......@@ -560,12 +578,11 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
),
child: new BlockBody(
mainAxis: config.mainAxis,
children: _divideSlices(context, slices, keys)
children: slices
)
)
);
slices = <Widget>[];
keys = <Key>[];
}
return new _MergeableMaterialBlockBody(
......@@ -578,7 +595,7 @@ class _MergeableMaterialState extends State<MergeableMaterial> {
}
// The parent hierarchy can change and lead to the slice being
// rebuilt. Usinga global key solves the issue.
// rebuilt. Using a global key solves the issue.
class _MergeableMaterialSliceKey extends GlobalKey {
const _MergeableMaterialSliceKey(this.value) : super.constructor();
......
......@@ -1014,12 +1014,14 @@ void main() {
matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round);
});
bool isDivider(Widget widget) {
bool isDivider(Widget widget, bool top, bool bottom) {
final DecoratedBox box = widget;
final BorderSide side = new BorderSide(color: const Color(0x1F000000), width: 0.5);
return box.decoration == new BoxDecoration(
border: new Border(
bottom: new BorderSide(color: const Color(0x1F000000))
top: top ? side : BorderSide.none,
bottom: bottom ? side : BorderSide.none
)
);
}
......@@ -1068,10 +1070,10 @@ void main() {
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);
expect(isDivider(boxes[offset], false, true), isTrue);
expect(isDivider(boxes[offset + 1], true, true), isTrue);
expect(isDivider(boxes[offset + 2], true, true), isTrue);
expect(isDivider(boxes[offset + 3], true, false), isTrue);
await tester.pumpWidget(
new Scaffold(
......@@ -1116,13 +1118,16 @@ void main() {
)
);
// Wait for dividers to shrink.
await tester.pump(const Duration(milliseconds: 200));
boxes = tester.widgetList(find.byType(DecoratedBox)).toList();
offset = 3;
expect(isDivider(boxes[offset]), isTrue);
expect(isDivider(boxes[offset + 1]), isFalse);
expect(isDivider(boxes[offset], false, true), isTrue);
expect(isDivider(boxes[offset + 1], true, false), isTrue);
// offset + 2 is gap
expect(isDivider(boxes[offset + 3]), isTrue);
expect(isDivider(boxes[offset + 4]), isFalse);
expect(isDivider(boxes[offset + 3], false, true), isTrue);
expect(isDivider(boxes[offset + 4], true, false), isTrue);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment