Unverified Commit 236acb52 authored by Natalie Sampsell's avatar Natalie Sampsell Committed by GitHub

Segmented control animation (#18811)

Added animation to segmented control widget.
parent 03a1f4ac
...@@ -23,6 +23,10 @@ const double _kMinSegmentedControlHeight = 28.0; ...@@ -23,6 +23,10 @@ const double _kMinSegmentedControlHeight = 28.0;
// press or drag. // press or drag.
const Color _kPressedBackground = const Color(0x33007aff); const Color _kPressedBackground = const Color(0x33007aff);
// The duration of the fade animation used to transition when a new widget
// is selected.
const Duration _kFadeDuration = const Duration(milliseconds: 165);
/// An iOS-style segmented control. /// An iOS-style segmented control.
/// ///
/// Displays the widgets provided in the [Map] of [children] in a /// Displays the widgets provided in the [Map] of [children] in a
...@@ -147,19 +151,68 @@ class SegmentedControl<T> extends StatefulWidget { ...@@ -147,19 +151,68 @@ class SegmentedControl<T> extends StatefulWidget {
_SegmentedControlState<T> createState() => _SegmentedControlState<T>(); _SegmentedControlState<T> createState() => _SegmentedControlState<T>();
} }
class _SegmentedControlState<T> extends State<SegmentedControl<T>> { class _SegmentedControlState<T> extends State<SegmentedControl<T>>
with TickerProviderStateMixin<SegmentedControl<T>> {
T _pressedKey; T _pressedKey;
void _onTapDown(T currentKey) { final List<AnimationController> _selectionControllers = <AnimationController>[];
setState(() { final List<ColorTween> _childTweens = <ColorTween>[];
_pressedKey = currentKey;
}); static final ColorTween forwardBackgroundColorTween = new ColorTween(
begin: _kPressedBackground,
end: CupertinoColors.activeBlue,
);
static final ColorTween reverseBackgroundColorTween = new ColorTween(
begin: CupertinoColors.white,
end: CupertinoColors.activeBlue,
);
static final ColorTween textColorTween = new ColorTween(
begin: CupertinoColors.activeBlue,
end: CupertinoColors.white,
);
@override
void initState() {
super.initState();
for (T key in widget.children.keys) {
final AnimationController animationController = createAnimationController();
if (widget.groupValue == key) {
_childTweens.add(reverseBackgroundColorTween);
animationController.value = 1.0;
} else {
_childTweens.add(forwardBackgroundColorTween);
}
_selectionControllers.add(animationController);
}
} }
void _onTapUp(TapUpDetails event) { AnimationController createAnimationController() {
setState(() { return new AnimationController(
_pressedKey = null; duration: _kFadeDuration,
}); vsync: this,
)..addListener(() {
setState(() {
// State of background/text colors has changed
});
});
}
@override
void dispose() {
for (AnimationController animationController in _selectionControllers) {
animationController.dispose();
}
super.dispose();
}
void _onTapDown(T currentKey) {
if (_pressedKey == null && currentKey != widget.groupValue) {
setState(() {
_pressedKey = currentKey;
});
}
} }
void _onTapCancel() { void _onTapCancel() {
...@@ -169,14 +222,69 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> { ...@@ -169,14 +222,69 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
} }
void _onTap(T currentKey) { void _onTap(T currentKey) {
if (currentKey != widget.groupValue) { if (currentKey != widget.groupValue && currentKey == _pressedKey) {
widget.onValueChanged(currentKey); widget.onValueChanged(currentKey);
_pressedKey = null;
}
}
Color getTextColor(int index, T currentKey) {
if (_selectionControllers[index].isAnimating)
return textColorTween.evaluate(_selectionControllers[index]);
if (widget.groupValue == currentKey)
return CupertinoColors.white;
return CupertinoColors.activeBlue;
}
Color getBackgroundColor(int index, T currentKey) {
if (_selectionControllers[index].isAnimating)
return _childTweens[index].evaluate(_selectionControllers[index]);
if (widget.groupValue == currentKey)
return CupertinoColors.activeBlue;
if (_pressedKey == currentKey)
return _kPressedBackground;
return CupertinoColors.white;
}
void updateAnimationControllers() {
if (_selectionControllers.length > widget.children.length) {
_selectionControllers.length = widget.children.length;
_childTweens.length = widget.children.length;
} else {
for (int index = _selectionControllers.length; index < widget.children.length; index += 1) {
_selectionControllers.add(createAnimationController());
_childTweens.add(reverseBackgroundColorTween);
}
}
}
@override
void didUpdateWidget(SegmentedControl<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.children.length != widget.children.length) {
updateAnimationControllers();
}
if (oldWidget.groupValue != widget.groupValue) {
int index = 0;
for (T key in widget.children.keys) {
if (widget.groupValue == key) {
_childTweens[index] = forwardBackgroundColorTween;
_selectionControllers[index].forward();
} else {
_childTweens[index] = reverseBackgroundColorTween;
_selectionControllers[index].reverse();
}
index += 1;
}
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<Widget> gestureChildren = <Widget>[]; final List<Widget> _gestureChildren = <Widget>[];
final List<Color> _backgroundColors = <Color>[];
int index = 0; int index = 0;
int selectedIndex; int selectedIndex;
int pressedIndex; int pressedIndex;
...@@ -185,12 +293,10 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> { ...@@ -185,12 +293,10 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex; pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex;
final TextStyle textStyle = DefaultTextStyle.of(context).style.copyWith( final TextStyle textStyle = DefaultTextStyle.of(context).style.copyWith(
color: (widget.groupValue == currentKey) ? color: getTextColor(index, currentKey),
CupertinoColors.white : CupertinoColors.activeBlue,
); );
final IconThemeData iconTheme = new IconThemeData( final IconThemeData iconTheme = new IconThemeData(
color: (widget.groupValue == currentKey) ? color: getTextColor(index, currentKey),
CupertinoColors.white : CupertinoColors.activeBlue,
); );
Widget child = widget.children[currentKey]; Widget child = widget.children[currentKey];
...@@ -198,7 +304,6 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> { ...@@ -198,7 +304,6 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
onTapDown: (TapDownDetails event) { onTapDown: (TapDownDetails event) {
_onTapDown(currentKey); _onTapDown(currentKey);
}, },
onTapUp: _onTapUp,
onTapCancel: _onTapCancel, onTapCancel: _onTapCancel,
onTap: () { onTap: () {
_onTap(currentKey); _onTap(currentKey);
...@@ -215,14 +320,17 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> { ...@@ -215,14 +320,17 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
), ),
), ),
); );
gestureChildren.add(child);
_backgroundColors.add(getBackgroundColor(index, currentKey));
_gestureChildren.add(child);
index += 1; index += 1;
} }
final Widget box = new _SegmentedControlRenderWidget<T>( final Widget box = new _SegmentedControlRenderWidget<T>(
children: gestureChildren, children: _gestureChildren,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
pressedIndex: pressedIndex, pressedIndex: pressedIndex,
backgroundColors: _backgroundColors,
); );
return new Padding( return new Padding(
...@@ -241,6 +349,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget { ...@@ -241,6 +349,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
List<Widget> children = const <Widget>[], List<Widget> children = const <Widget>[],
@required this.selectedIndex, @required this.selectedIndex,
@required this.pressedIndex, @required this.pressedIndex,
@required this.backgroundColors,
}) : super( }) : super(
key: key, key: key,
children: children, children: children,
...@@ -248,6 +357,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget { ...@@ -248,6 +357,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
final int selectedIndex; final int selectedIndex;
final int pressedIndex; final int pressedIndex;
final List<Color> backgroundColors;
@override @override
RenderObject createRenderObject(BuildContext context) { RenderObject createRenderObject(BuildContext context) {
...@@ -255,6 +365,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget { ...@@ -255,6 +365,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
pressedIndex: pressedIndex, pressedIndex: pressedIndex,
backgroundColors: backgroundColors,
); );
} }
...@@ -263,7 +374,8 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget { ...@@ -263,7 +374,8 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
renderObject renderObject
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
..selectedIndex = selectedIndex ..selectedIndex = selectedIndex
..pressedIndex = pressedIndex; ..pressedIndex = pressedIndex
..backgroundColors = backgroundColors;
} }
} }
...@@ -281,10 +393,12 @@ class _RenderSegmentedControl<T> extends RenderBox ...@@ -281,10 +393,12 @@ class _RenderSegmentedControl<T> extends RenderBox
@required int selectedIndex, @required int selectedIndex,
@required int pressedIndex, @required int pressedIndex,
@required TextDirection textDirection, @required TextDirection textDirection,
@required List<Color> backgroundColors,
}) : assert(textDirection != null), }) : assert(textDirection != null),
_textDirection = textDirection, _textDirection = textDirection,
_selectedIndex = selectedIndex, _selectedIndex = selectedIndex,
_pressedIndex = pressedIndex { _pressedIndex = pressedIndex,
_backgroundColors = backgroundColors {
addAll(children); addAll(children);
} }
...@@ -318,6 +432,16 @@ class _RenderSegmentedControl<T> extends RenderBox ...@@ -318,6 +432,16 @@ class _RenderSegmentedControl<T> extends RenderBox
markNeedsLayout(); markNeedsLayout();
} }
List<Color> get backgroundColors => _backgroundColors;
List<Color> _backgroundColors;
set backgroundColors(List<Color> value) {
if (_backgroundColors == value) {
return;
}
_backgroundColors = value;
markNeedsPaint();
}
final Paint _outlinePaint = new Paint() final Paint _outlinePaint = new Paint()
..color = CupertinoColors.activeBlue ..color = CupertinoColors.activeBlue
..strokeWidth = 1.0 ..strokeWidth = 1.0
...@@ -481,17 +605,10 @@ class _RenderSegmentedControl<T> extends RenderBox ...@@ -481,17 +605,10 @@ class _RenderSegmentedControl<T> extends RenderBox
final _SegmentedControlContainerBoxParentData childParentData = child.parentData; final _SegmentedControlContainerBoxParentData childParentData = child.parentData;
Color color = CupertinoColors.white;
if (selectedIndex != null && selectedIndex == childIndex) {
color = CupertinoColors.activeBlue;
} else if (pressedIndex != null && pressedIndex == childIndex) {
color = _kPressedBackground;
}
context.canvas.drawRRect( context.canvas.drawRRect(
childParentData.surroundingRect.shift(offset), childParentData.surroundingRect.shift(offset),
new Paint() new Paint()
..color = color ..color = backgroundColors[childIndex]
..style = PaintingStyle.fill, ..style = PaintingStyle.fill,
); );
context.canvas.drawRRect( context.canvas.drawRRect(
...@@ -505,6 +622,14 @@ class _RenderSegmentedControl<T> extends RenderBox ...@@ -505,6 +622,14 @@ class _RenderSegmentedControl<T> extends RenderBox
@override @override
bool hitTestChildren(HitTestResult result, {@required Offset position}) { bool hitTestChildren(HitTestResult result, {@required Offset position}) {
assert(position != null); assert(position != null);
return defaultHitTestChildren(result, position: position); RenderBox child = lastChild;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData;
if (childParentData.surroundingRect.contains(position)) {
return child.hitTest(result, position: (Offset.zero & child.size).center);
}
child = childParentData.previousSibling;
}
return false;
} }
} }
...@@ -8,7 +8,6 @@ import 'package:flutter/widgets.dart'; ...@@ -8,7 +8,6 @@ import 'package:flutter/widgets.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
dynamic getRenderSegmentedControl(WidgetTester tester) { dynamic getRenderSegmentedControl(WidgetTester tester) {
...@@ -23,7 +22,6 @@ StatefulBuilder setupSimpleSegmentedControl() { ...@@ -23,7 +22,6 @@ StatefulBuilder setupSimpleSegmentedControl() {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
int sharedValue = 0; int sharedValue = 0;
return new StatefulBuilder( return new StatefulBuilder(
...@@ -50,6 +48,10 @@ Widget boilerplate({Widget child}) { ...@@ -50,6 +48,10 @@ Widget boilerplate({Widget child}) {
); );
} }
Color getBackgroundColor(WidgetTester tester, int childIndex) {
return getRenderSegmentedControl(tester).backgroundColors[childIndex];
}
void main() { void main() {
testWidgets('Tap changes toggle state', (WidgetTester tester) async { testWidgets('Tap changes toggle state', (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
...@@ -96,8 +98,7 @@ void main() { ...@@ -96,8 +98,7 @@ void main() {
), ),
), ),
); );
fail( fail('Should not be possible to create a segmented control with no children');
'Should not be possible to create a segmented control with no children');
} on AssertionError catch (e) { } on AssertionError catch (e) {
expect(e.toString(), contains('children.length')); expect(e.toString(), contains('children.length'));
} }
...@@ -112,15 +113,14 @@ void main() { ...@@ -112,15 +113,14 @@ void main() {
), ),
), ),
); );
fail( fail('Should not be possible to create a segmented control with just one child');
'Should not be possible to create a segmented control with just one child');
} on AssertionError catch (e) { } on AssertionError catch (e) {
expect(e.toString(), contains('children.length')); expect(e.toString(), contains('children.length'));
} }
}); });
testWidgets('Value attribute must be the key of one of the children widgets', testWidgets('Value attribute must be the key of one of the children widgets',
(WidgetTester tester) async { (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -142,8 +142,7 @@ void main() { ...@@ -142,8 +142,7 @@ void main() {
} }
}); });
testWidgets('Children and onValueChanged can not be null', testWidgets('Children and onValueChanged can not be null', (WidgetTester tester) async {
(WidgetTester tester) async {
try { try {
await tester.pumpWidget( await tester.pumpWidget(
boilerplate( boilerplate(
...@@ -153,8 +152,7 @@ void main() { ...@@ -153,8 +152,7 @@ void main() {
), ),
), ),
); );
fail( fail('Should not be possible to create segmented control with null children');
'Should not be possible to create segmented control with null children');
} on AssertionError catch (e) { } on AssertionError catch (e) {
expect(e.toString(), contains('children')); expect(e.toString(), contains('children'));
} }
...@@ -172,16 +170,14 @@ void main() { ...@@ -172,16 +170,14 @@ void main() {
), ),
), ),
); );
fail( fail('Should not be possible to create segmented control with null onValueChanged');
'Should not be possible to create segmented control with null onValueChanged');
} on AssertionError catch (e) { } on AssertionError catch (e) {
expect(e.toString(), contains('onValueChanged')); expect(e.toString(), contains('onValueChanged'));
} }
}); });
testWidgets( testWidgets('Widgets have correct default text/icon styles, change correctly on selection',
'Widgets have correct default text/icon styles, change correctly on selection', (WidgetTester tester) async {
(WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Icon(IconData(1)); children[1] = const Icon(IconData(1));
...@@ -206,20 +202,19 @@ void main() { ...@@ -206,20 +202,19 @@ void main() {
), ),
); );
DefaultTextStyle textStyle = await tester.pumpAndSettle();
tester.widget(find.widgetWithText(DefaultTextStyle, 'Child 1'));
IconTheme iconTheme = DefaultTextStyle textStyle = tester.widget(find.widgetWithText(DefaultTextStyle, 'Child 1'));
tester.widget(find.widgetWithIcon(IconTheme, const IconData(1))); IconTheme iconTheme = tester.widget(find.widgetWithIcon(IconTheme, const IconData(1)));
expect(textStyle.style.color, CupertinoColors.white); expect(textStyle.style.color, CupertinoColors.white);
expect(iconTheme.data.color, CupertinoColors.activeBlue); expect(iconTheme.data.color, CupertinoColors.activeBlue);
await tester.tap(find.widgetWithIcon(IconTheme, const IconData(1))); await tester.tap(find.widgetWithIcon(IconTheme, const IconData(1)));
await tester.pump(); await tester.pumpAndSettle();
textStyle = tester.widget(find.widgetWithText(DefaultTextStyle, 'Child 1')); textStyle = tester.widget(find.widgetWithText(DefaultTextStyle, 'Child 1'));
iconTheme = iconTheme = tester.widget(find.widgetWithIcon(IconTheme, const IconData(1)));
tester.widget(find.widgetWithIcon(IconTheme, const IconData(1)));
expect(textStyle.style.color, CupertinoColors.activeBlue); expect(textStyle.style.color, CupertinoColors.activeBlue);
expect(iconTheme.data.color, CupertinoColors.white); expect(iconTheme.data.color, CupertinoColors.white);
...@@ -254,9 +249,8 @@ void main() { ...@@ -254,9 +249,8 @@ void main() {
expect(value, isTrue); expect(value, isTrue);
}); });
testWidgets( testWidgets('State does not change if onValueChanged does not call setState()',
'State does not change if onValueChanged does not call setState()', (WidgetTester tester) async {
(WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -277,49 +271,14 @@ void main() { ...@@ -277,49 +271,14 @@ void main() {
), ),
); );
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
await tester.tap(find.text('Child 2')); await tester.tap(find.text('Child 2'));
await tester.pump(); await tester.pump();
expect( expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester), expect(getBackgroundColor(tester, 1), CupertinoColors.white);
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
}); });
testWidgets( testWidgets(
...@@ -327,47 +286,17 @@ void main() { ...@@ -327,47 +286,17 @@ void main() {
'and should not change when tapped again', (WidgetTester tester) async { 'and should not change when tapped again', (WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.pumpWidget(setupSimpleSegmentedControl());
final dynamic childList = expect(getBackgroundColor(tester, 1), CupertinoColors.white);
getRenderSegmentedControl(tester).getChildrenAsList();
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
await tester.tap(find.text('Child 2')); await tester.tap(find.text('Child 2'));
await tester.pump(); await tester.pumpAndSettle(const Duration(milliseconds: 200));
expect( expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
await tester.tap(find.text('Child 2')); await tester.tap(find.text('Child 2'));
await tester.pump(); await tester.pump();
expect( expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
}); });
testWidgets( testWidgets(
...@@ -404,36 +333,17 @@ void main() { ...@@ -404,36 +333,17 @@ void main() {
); );
testWidgets('Passed in value is child initially selected', testWidgets('Passed in value is child initially selected',
(WidgetTester tester) async { (WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.pumpWidget(setupSimpleSegmentedControl());
expect(getRenderSegmentedControl(tester).selectedIndex, 0); expect(getRenderSegmentedControl(tester).selectedIndex, 0);
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
}); });
testWidgets('Null input for value results in no child initially selected', testWidgets('Null input for value results in no child initially selected',
(WidgetTester tester) async { (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -460,132 +370,42 @@ void main() { ...@@ -460,132 +370,42 @@ void main() {
expect(getRenderSegmentedControl(tester).selectedIndex, null); expect(getRenderSegmentedControl(tester).selectedIndex, null);
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.white);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
}); });
testWidgets('Long press changes background color of not-selected child', testWidgets('Long press changes background color of not-selected child',
(WidgetTester tester) async { (WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.pumpWidget(setupSimpleSegmentedControl());
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
final Offset center = tester.getCenter(find.text('Child 2')); final Offset center = tester.getCenter(find.text('Child 2'));
await tester.startGesture(center); await tester.startGesture(center);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester), expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: const Color(0x33007aff),
),
);
}); });
testWidgets( testWidgets('Long press does not change background color of currently-selected child',
'Long press does not change background color of currently-selected child', (WidgetTester tester) async {
(WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.pumpWidget(setupSimpleSegmentedControl());
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
final Offset center = tester.getCenter(find.text('Child 1')); final Offset center = tester.getCenter(find.text('Child 1'));
await tester.startGesture(center); await tester.startGesture(center);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester), expect(getBackgroundColor(tester, 1), CupertinoColors.white);
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
}); });
testWidgets('Height of segmented control is determined by tallest widget', testWidgets('Height of segmented control is determined by tallest widget',
(WidgetTester tester) async { (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = new Container( children[0] = new Container(
constraints: const BoxConstraints.tightFor(height: 100.0), constraints: const BoxConstraints.tightFor(height: 100.0),
...@@ -611,16 +431,15 @@ void main() { ...@@ -611,16 +431,15 @@ void main() {
), ),
); );
final RenderBox buttonBox = tester final RenderBox buttonBox = tester.renderObject(
.renderObject(find.byKey(const ValueKey<String>('Segmented Control'))); find.byKey(const ValueKey<String>('Segmented Control')));
// Default height of Placeholder is 400.0px, which is greater than heights // Default height of Placeholder is 400.0px, which is greater than heights
// of other child widgets. // of other child widgets.
expect(buttonBox.size.height, 400.0); expect(buttonBox.size.height, 400.0);
}); });
testWidgets('Width of each child widget is the same', testWidgets('Width of each child widget is the same', (WidgetTester tester) async {
(WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = new Container(); children[0] = new Container();
children[1] = const Placeholder(); children[1] = const Placeholder();
...@@ -640,23 +459,22 @@ void main() { ...@@ -640,23 +459,22 @@ void main() {
), ),
); );
final RenderBox segmentedControl = tester final RenderBox segmentedControl = tester.renderObject(
.renderObject(find.byKey(const ValueKey<String>('Segmented Control'))); find.byKey(const ValueKey<String>('Segmented Control')));
// Subtract the 16.0px from each side. Remaining width should be allocated // Subtract the 16.0px from each side. Remaining width should be allocated
// to each child equally. // to each child equally.
final double childWidth = (segmentedControl.size.width - 32.0) / 3; final double childWidth = (segmentedControl.size.width - 32.0) / 3;
final dynamic childList = expect(childWidth,
getRenderSegmentedControl(tester).getChildrenAsList(); getRenderSegmentedControl(tester).getChildrenAsList()[0].parentData.surroundingRect.width);
expect(childWidth,
for (dynamic child in childList) { getRenderSegmentedControl(tester).getChildrenAsList()[1].parentData.surroundingRect.width);
expect(childWidth, child.parentData.surroundingRect.width); expect(childWidth,
} getRenderSegmentedControl(tester).getChildrenAsList()[2].parentData.surroundingRect.width);
}); });
testWidgets('Width is finite in unbounded space', testWidgets('Width is finite in unbounded space', (WidgetTester tester) async {
(WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -679,14 +497,14 @@ void main() { ...@@ -679,14 +497,14 @@ void main() {
), ),
); );
final RenderBox segmentedControl = tester final RenderBox segmentedControl = tester.renderObject(
.renderObject(find.byKey(const ValueKey<String>('Segmented Control'))); find.byKey(const ValueKey<String>('Segmented Control')));
expect(segmentedControl.size.width.isFinite, isTrue); expect(segmentedControl.size.width.isFinite, isTrue);
}); });
testWidgets('Directionality test - RTL should reverse order of widgets', testWidgets('Directionality test - RTL should reverse order of widgets',
(WidgetTester tester) async { (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -703,14 +521,12 @@ void main() { ...@@ -703,14 +521,12 @@ void main() {
), ),
); );
expect( expect(tester.getTopRight(find.text('Child 1')).dx >
tester.getTopRight(find.text('Child 1')).dx > tester.getTopRight(find.text('Child 2')).dx, isTrue);
tester.getTopRight(find.text('Child 2')).dx,
isTrue);
}); });
testWidgets('Correct initial selection and toggling behavior - RTL', testWidgets('Correct initial selection and toggling behavior - RTL',
(WidgetTester tester) async { (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{}; final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1'); children[0] = const Text('Child 1');
children[1] = const Text('Child 2'); children[1] = const Text('Child 2');
...@@ -738,63 +554,19 @@ void main() { ...@@ -738,63 +554,19 @@ void main() {
), ),
); );
final dynamic childList = expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester).getChildrenAsList(); expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(
getRenderSegmentedControl(tester),
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
await tester.tap(find.text('Child 2')); await tester.tap(find.text('Child 2'));
await tester.pump(); await tester.pumpAndSettle();
expect( expect(getBackgroundColor(tester, 0), CupertinoColors.white);
getRenderSegmentedControl(tester), expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
paints
..rrect(
rrect: childList.elementAt(0).parentData.surroundingRect,
color: CupertinoColors.white,
),
);
expect(
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
await tester.tap(find.text('Child 2')); await tester.tap(find.text('Child 2'));
await tester.pump(); await tester.pump();
expect( expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
getRenderSegmentedControl(tester),
paints
..rrect()
..rrect()
..rrect(
rrect: childList.elementAt(1).parentData.surroundingRect,
color: CupertinoColors.activeBlue,
),
);
}); });
testWidgets('Segmented control semantics', (WidgetTester tester) async { testWidgets('Segmented control semantics', (WidgetTester tester) async {
...@@ -894,6 +666,504 @@ void main() { ...@@ -894,6 +666,504 @@ void main() {
semantics.dispose(); semantics.dispose();
}); });
testWidgets('Non-centered taps work on smaller widgets', (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
int sharedValue = 1;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
);
expect(sharedValue, 1);
final double childWidth = getRenderSegmentedControl(tester).firstChild.size.width;
final Offset centerOfSegmentedControl = tester.getCenter(find.text('A'));
// Tap just inside segment bounds
await tester.tapAt(new Offset(childWidth - 10.0, centerOfSegmentedControl.dy));
expect(sharedValue, 0);
});
testWidgets('Animation is correct when the selected segment changes',
(WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl());
await tester.tap(find.text('Child 2'));
await tester.pump();
expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff7bbaff));
expect(getBackgroundColor(tester, 1), const Color(0x95007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xffb9daff));
expect(getBackgroundColor(tester, 1), const Color(0xc7007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xfff7faff));
expect(getBackgroundColor(tester, 1), const Color(0xf8007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), CupertinoColors.white);
expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
});
testWidgets('Animation is correct when widget is rebuilt', (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('Child 1');
children[1] = const Text('Child 2');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
);
await tester.tap(find.text('Child 2'));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
);
expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
const Duration(milliseconds: 40),
);
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
const Duration(milliseconds: 40),
);
expect(getBackgroundColor(tester, 0), const Color(0xff7bbaff));
expect(getBackgroundColor(tester, 1), const Color(0x95007aff));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
const Duration(milliseconds: 40),
);
expect(getBackgroundColor(tester, 0), const Color(0xffb9daff));
expect(getBackgroundColor(tester, 1), const Color(0xc7007aff));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
const Duration(milliseconds: 40),
);
expect(getBackgroundColor(tester, 0), const Color(0xfff7faff));
expect(getBackgroundColor(tester, 1), const Color(0xf8007aff));
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
const Duration(milliseconds: 40),
);
expect(getBackgroundColor(tester, 0), CupertinoColors.white);
expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
});
testWidgets('Multiple segments are pressed', (WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
children[2] = const Text('C');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
);
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
await tester.startGesture(tester.getCenter(find.text('B')));
await tester.pumpAndSettle(const Duration(milliseconds: 200));
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
expect(getBackgroundColor(tester, 2), CupertinoColors.white);
await tester.startGesture(tester.getCenter(find.text('C')));
await tester.pumpAndSettle(const Duration(milliseconds: 200));
// Press on C has no effect while B is held down.
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
expect(getBackgroundColor(tester, 2), CupertinoColors.white);
});
testWidgets('Transition is triggered while a transition is already occurring',
(WidgetTester tester) async {
final Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
children[2] = const Text('C');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
},
groupValue: sharedValue,
),
);
},
),
);
await tester.tap(find.text('B'));
await tester.pump();
expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
// While A to B transition is occurring, press on C.
await tester.tap(find.text('C'));
await tester.pump();
// A and B are now both transitioning to white.
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0xffc1deff));
expect(getBackgroundColor(tester, 2), const Color(0x33007aff));
await tester.pump(const Duration(milliseconds: 40));
// B background color has reached unselected state.
expect(getBackgroundColor(tester, 0), const Color(0xff7bbaff));
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
expect(getBackgroundColor(tester, 2), const Color(0x64007aff));
await tester.pump(const Duration(milliseconds: 100));
// A background color has reached unselected state.
expect(getBackgroundColor(tester, 0), CupertinoColors.white);
expect(getBackgroundColor(tester, 2), const Color(0xe0007aff));
await tester.pump(const Duration(milliseconds: 40));
// C background color has reached selected state.
expect(getBackgroundColor(tester, 2), CupertinoColors.activeBlue);
});
testWidgets('Segment is selected while it is transitioning to unselected state',
(WidgetTester tester) async {
await tester.pumpWidget(setupSimpleSegmentedControl());
await tester.tap(find.text('Child 2'));
await tester.pump();
expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
// While A to B transition is occurring, press on A again.
await tester.tap(find.text('Child 1'));
await tester.pump();
// Both transitions start to reverse.
expect(getBackgroundColor(tester, 0), const Color(0xcd007aff));
expect(getBackgroundColor(tester, 1), const Color(0xffc1deff));
await tester.pump(const Duration(milliseconds: 40));
// A and B finish transitioning.
expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
});
testWidgets('Add segment while animation is running', (WidgetTester tester) async {
Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
children[2] = const Text('C');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
if (sharedValue == 1) {
children = new Map<int, Widget>.from(children);
children[3] = const Text('D');
}
},
groupValue: sharedValue,
),
);
},
),
);
await tester.tap(find.text('B'));
await tester.pump();
expect(getBackgroundColor(tester, 0), const Color(0xff007aff));
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
expect(getBackgroundColor(tester, 3), CupertinoColors.white);
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
expect(getBackgroundColor(tester, 3), CupertinoColors.white);
await tester.pump(const Duration(milliseconds: 150));
expect(getBackgroundColor(tester, 0), CupertinoColors.white);
expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
expect(getBackgroundColor(tester, 3), CupertinoColors.white);
});
testWidgets('Remove segment while animation is running', (WidgetTester tester) async {
Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
children[2] = const Text('C');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
if (sharedValue == 1) {
children.remove(2);
children = new Map<int, Widget>.from(children);
}
},
groupValue: sharedValue,
),
);
},
),
);
expect(getRenderSegmentedControl(tester).getChildrenAsList().length, 3);
await tester.tap(find.text('B'));
await tester.pump();
expect(getBackgroundColor(tester, 1), const Color(0x33007aff));
expect(getRenderSegmentedControl(tester).getChildrenAsList().length, 2);
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 1), const Color(0x64007aff));
await tester.pump(const Duration(milliseconds: 150));
expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue);
});
testWidgets('Remove currently animating segment', (WidgetTester tester) async {
Map<int, Widget> children = <int, Widget>{};
children[0] = const Text('A');
children[1] = const Text('B');
children[2] = const Text('C');
int sharedValue = 0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return boilerplate(
child: new SegmentedControl<int>(
key: const ValueKey<String>('Segmented Control'),
children: children,
onValueChanged: (int newValue) {
setState(() {
sharedValue = newValue;
});
if (sharedValue == 1) {
children.remove(1);
children = new Map<int, Widget>.from(children);
sharedValue = null;
}
},
groupValue: sharedValue,
),
);
},
),
);
expect(getRenderSegmentedControl(tester).getChildrenAsList().length, 3);
await tester.tap(find.text('B'));
await tester.pump();
expect(getRenderSegmentedControl(tester).getChildrenAsList().length, 2);
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff3d9aff));
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
await tester.pump(const Duration(milliseconds: 40));
expect(getBackgroundColor(tester, 0), const Color(0xff7bbaff));
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
await tester.pump(const Duration(milliseconds: 100));
expect(getBackgroundColor(tester, 0), CupertinoColors.white);
expect(getBackgroundColor(tester, 1), CupertinoColors.white);
});
testWidgets('Golden Test Placeholder Widget', (WidgetTester tester) async { testWidgets('Golden Test Placeholder Widget', (WidgetTester tester) async {
// Different machines render this content differently. Since the golden // Different machines render this content differently. Since the golden
// files are rendered on MacOS, this test should only be run on MacOS. // files are rendered on MacOS, this test should only be run on MacOS.
......
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