mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add ability to disable CupertinoSegmentedControl (#152813)
### Summary Add the ability to configure enabled or disabled segments in CupertinoSegmentedControl. The idea is to pass a `segmentStates` map, where the user can set the state according to segment key. User can also set background and text colors when the segment is disabled. ### Demo https://github.com/user-attachments/assets/4a02da02-a0fb-4ded-a271-033a8dc79ac3 ### Related issue Fixes https://github.com/flutter/flutter/issues/52105
This commit is contained in:
parent
0167f02e90
commit
fa5254331f
@ -37,6 +37,9 @@ class SegmentedControlExample extends StatefulWidget {
|
|||||||
|
|
||||||
class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
||||||
Sky _selectedSegment = Sky.midnight;
|
Sky _selectedSegment = Sky.midnight;
|
||||||
|
bool _toggleOne = false;
|
||||||
|
bool _toggleAll = true;
|
||||||
|
Set<Sky> _disabledChildren = <Sky>{};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -45,6 +48,7 @@ class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
|||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
// This Cupertino segmented control has the enum "Sky" as the type.
|
// This Cupertino segmented control has the enum "Sky" as the type.
|
||||||
middle: CupertinoSegmentedControl<Sky>(
|
middle: CupertinoSegmentedControl<Sky>(
|
||||||
|
disabledChildren: _disabledChildren,
|
||||||
selectedColor: skyColors[_selectedSegment],
|
selectedColor: skyColors[_selectedSegment],
|
||||||
// Provide horizontal padding around the children.
|
// Provide horizontal padding around the children.
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
@ -73,9 +77,60 @@ class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Column(
|
||||||
'Selected Segment: ${_selectedSegment.name}',
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
style: const TextStyle(color: CupertinoColors.white),
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
'Selected Segment: ${_selectedSegment.name}',
|
||||||
|
style: const TextStyle(color: CupertinoColors.white),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const Text('Disable one segment', style: TextStyle(color: CupertinoColors.white)),
|
||||||
|
CupertinoSwitch(
|
||||||
|
value: _toggleOne,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
setState(() {
|
||||||
|
_toggleOne = value;
|
||||||
|
if (value) {
|
||||||
|
_toggleAll = false;
|
||||||
|
_disabledChildren = <Sky>{Sky.midnight};
|
||||||
|
} else {
|
||||||
|
_toggleAll = true;
|
||||||
|
_disabledChildren = <Sky>{};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const Text('Toggle all segments', style: TextStyle(color: CupertinoColors.white)),
|
||||||
|
CupertinoSwitch(
|
||||||
|
value: _toggleAll,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
setState(() {
|
||||||
|
_toggleAll = value;
|
||||||
|
if (value) {
|
||||||
|
_toggleOne = false;
|
||||||
|
_disabledChildren = <Sky>{};
|
||||||
|
} else {
|
||||||
|
_disabledChildren = <Sky>{
|
||||||
|
Sky.midnight,
|
||||||
|
Sky.viridian,
|
||||||
|
Sky.cerulean,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -2,10 +2,43 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_api_samples/cupertino/segmented_control/cupertino_segmented_control.0.dart' as example;
|
import 'package:flutter_api_samples/cupertino/segmented_control/cupertino_segmented_control.0.dart' as example;
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
testWidgets('Verify initial state', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.SegmentedControlApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Midnight is the default selected segment.
|
||||||
|
expect(find.text('Selected Segment: midnight'), findsOneWidget);
|
||||||
|
|
||||||
|
// All segments are enabled and can be selected.
|
||||||
|
await tester.tap(find.text('Viridian'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: viridian'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Cerulean'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: cerulean'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Midnight'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: midnight'), findsOneWidget);
|
||||||
|
|
||||||
|
// Verify that the first CupertinoSwitch is off.
|
||||||
|
final Finder firstSwitchFinder = find.byType(CupertinoSwitch).first;
|
||||||
|
final CupertinoSwitch firstSwitch = tester.widget<CupertinoSwitch>(firstSwitchFinder);
|
||||||
|
expect(firstSwitch.value, false);
|
||||||
|
|
||||||
|
// Verify that the second CupertinoSwitch is on.
|
||||||
|
final Finder secondSwitchFinder = find.byType(CupertinoSwitch).last;
|
||||||
|
final CupertinoSwitch secondSwitch = tester.widget<CupertinoSwitch>(secondSwitchFinder);
|
||||||
|
expect(secondSwitch.value, true);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Can change a selected segmented control', (WidgetTester tester) async {
|
testWidgets('Can change a selected segmented control', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const example.SegmentedControlApp(),
|
const example.SegmentedControlApp(),
|
||||||
@ -18,4 +51,50 @@ void main() {
|
|||||||
|
|
||||||
expect(find.text('Selected Segment: cerulean'), findsOneWidget);
|
expect(find.text('Selected Segment: cerulean'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Can not select on a disabled segment', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.SegmentedControlApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Toggle on the first CupertinoSwitch to disable the first segment.
|
||||||
|
final Finder firstSwitchFinder = find.byType(CupertinoSwitch).first;
|
||||||
|
await tester.tap(firstSwitchFinder);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final CupertinoSwitch firstSwitch = tester.widget<CupertinoSwitch>(firstSwitchFinder);
|
||||||
|
expect(firstSwitch.value, true);
|
||||||
|
|
||||||
|
// Tap on the second segment then tap back on the first segment.
|
||||||
|
// Verify that the selected segment is still the second segment.
|
||||||
|
await tester.tap(find.text('Viridian'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: viridian'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Midnight'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: viridian'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Can not select on all disabled segments', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const example.SegmentedControlApp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Toggle off the second CupertinoSwitch to disable all segments.
|
||||||
|
final Finder secondSwitchFinder = find.byType(CupertinoSwitch).last;
|
||||||
|
await tester.tap(secondSwitchFinder);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final CupertinoSwitch secondSwitch = tester.widget<CupertinoSwitch>(secondSwitchFinder);
|
||||||
|
expect(secondSwitch.value, false);
|
||||||
|
|
||||||
|
// Tap on the second segment and verify that the selected segment is still the first segment.
|
||||||
|
await tester.tap(find.text('Viridian'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: midnight'), findsOneWidget);
|
||||||
|
|
||||||
|
// Tap on the third segment and verify that the selected segment is still the first segment.
|
||||||
|
await tester.tap(find.text('Cerulean'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Selected Segment: midnight'), findsOneWidget);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ const EdgeInsetsGeometry _kHorizontalItemPadding = EdgeInsets.symmetric(horizont
|
|||||||
// Minimum height of the segmented control.
|
// Minimum height of the segmented control.
|
||||||
const double _kMinSegmentedControlHeight = 28.0;
|
const double _kMinSegmentedControlHeight = 28.0;
|
||||||
|
|
||||||
|
// The default color used for the text of the disabled segment.
|
||||||
|
const Color _kDisableTextColor = Color.fromARGB(115, 122, 122, 122);
|
||||||
|
|
||||||
// The duration of the fade animation used to transition when a new widget
|
// The duration of the fade animation used to transition when a new widget
|
||||||
// is selected.
|
// is selected.
|
||||||
const Duration _kFadeDuration = Duration(milliseconds: 165);
|
const Duration _kFadeDuration = Duration(milliseconds: 165);
|
||||||
@ -57,17 +60,26 @@ const Duration _kFadeDuration = Duration(milliseconds: 165);
|
|||||||
/// A segmented control may optionally be created with custom colors. The
|
/// A segmented control may optionally be created with custom colors. The
|
||||||
/// [unselectedColor], [selectedColor], [borderColor], and [pressedColor]
|
/// [unselectedColor], [selectedColor], [borderColor], and [pressedColor]
|
||||||
/// arguments can be used to override the segmented control's colors from
|
/// arguments can be used to override the segmented control's colors from
|
||||||
/// [CupertinoTheme] defaults.
|
/// [CupertinoTheme] defaults. The [disabledColor] and [disabledTextColor]
|
||||||
|
/// set the background and text colors of the segment when it is disabled.
|
||||||
|
///
|
||||||
|
/// The segmented control can be disabled by adding children to the [Set] of
|
||||||
|
/// [disabledChildren]. If the child is not present in the [Set], it is enabled
|
||||||
|
/// by default.
|
||||||
///
|
///
|
||||||
/// {@tool dartpad}
|
/// {@tool dartpad}
|
||||||
/// This example shows a [CupertinoSegmentedControl] with an enum type.
|
/// This example shows a [CupertinoSegmentedControl] with an enum type.
|
||||||
///
|
///
|
||||||
/// The callback provided to [onValueChanged] should update the state of
|
/// The callback provided to [onValueChanged] should update the state of
|
||||||
/// the parent [StatefulWidget] using the [State.setState] method, so that
|
/// the parent [StatefulWidget] using the [State.setState] method, so that
|
||||||
/// the parent gets rebuilt; for example:
|
/// the parent gets rebuilt.
|
||||||
|
///
|
||||||
|
/// This example also demonstrates how to use the [disabledChildren] property by
|
||||||
|
/// toggling each [Switch] to enable or disable the segments.
|
||||||
///
|
///
|
||||||
/// ** See code in examples/api/lib/cupertino/segmented_control/cupertino_segmented_control.0.dart **
|
/// ** See code in examples/api/lib/cupertino/segmented_control/cupertino_segmented_control.0.dart **
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [CupertinoSegmentedControl], a segmented control widget in the style used
|
/// * [CupertinoSegmentedControl], a segmented control widget in the style used
|
||||||
@ -98,7 +110,10 @@ class CupertinoSegmentedControl<T extends Object> extends StatefulWidget {
|
|||||||
this.selectedColor,
|
this.selectedColor,
|
||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.pressedColor,
|
this.pressedColor,
|
||||||
|
this.disabledColor,
|
||||||
|
this.disabledTextColor,
|
||||||
this.padding,
|
this.padding,
|
||||||
|
this.disabledChildren = const <Never>{},
|
||||||
}) : assert(children.length >= 2),
|
}) : assert(children.length >= 2),
|
||||||
assert(
|
assert(
|
||||||
groupValue == null || children.keys.any((T child) => child == groupValue),
|
groupValue == null || children.keys.any((T child) => child == groupValue),
|
||||||
@ -148,11 +163,26 @@ class CupertinoSegmentedControl<T extends Object> extends StatefulWidget {
|
|||||||
/// Defaults to the selectedColor at 20% opacity if null.
|
/// Defaults to the selectedColor at 20% opacity if null.
|
||||||
final Color? pressedColor;
|
final Color? pressedColor;
|
||||||
|
|
||||||
|
/// The color used to fill the background of the segment when it is disabled.
|
||||||
|
///
|
||||||
|
/// If null, this color will be 50% opacity of the [selectedColor] when
|
||||||
|
/// the segment is selected. If the segment is unselected, this color will be
|
||||||
|
/// set to [unselectedColor].
|
||||||
|
final Color? disabledColor;
|
||||||
|
|
||||||
|
/// The color used for the text of the segment when it is disabled.
|
||||||
|
final Color? disabledTextColor;
|
||||||
|
|
||||||
/// The CupertinoSegmentedControl will be placed inside this padding.
|
/// The CupertinoSegmentedControl will be placed inside this padding.
|
||||||
///
|
///
|
||||||
/// Defaults to EdgeInsets.symmetric(horizontal: 16.0)
|
/// Defaults to EdgeInsets.symmetric(horizontal: 16.0)
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
|
/// The set of identifying keys that correspond to the segments that should be disabled.
|
||||||
|
///
|
||||||
|
/// All segments are enabled by default.
|
||||||
|
final Set<T> disabledChildren;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CupertinoSegmentedControl<T>> createState() => _SegmentedControlState<T>();
|
State<CupertinoSegmentedControl<T>> createState() => _SegmentedControlState<T>();
|
||||||
}
|
}
|
||||||
@ -172,6 +202,9 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
Color? _unselectedColor;
|
Color? _unselectedColor;
|
||||||
Color? _borderColor;
|
Color? _borderColor;
|
||||||
Color? _pressedColor;
|
Color? _pressedColor;
|
||||||
|
Color? _selectedDisabledColor;
|
||||||
|
Color? _unselectedDisabledColor;
|
||||||
|
Color? _disabledTextColor;
|
||||||
|
|
||||||
AnimationController createAnimationController() {
|
AnimationController createAnimationController() {
|
||||||
return AnimationController(
|
return AnimationController(
|
||||||
@ -187,6 +220,11 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
bool _updateColors() {
|
bool _updateColors() {
|
||||||
assert(mounted, 'This should only be called after didUpdateDependencies');
|
assert(mounted, 'This should only be called after didUpdateDependencies');
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
final Color disabledTextColor = widget.disabledTextColor ?? _kDisableTextColor;
|
||||||
|
if (_disabledTextColor != disabledTextColor) {
|
||||||
|
changed = true;
|
||||||
|
_disabledTextColor = disabledTextColor;
|
||||||
|
}
|
||||||
final Color selectedColor = widget.selectedColor ?? CupertinoTheme.of(context).primaryColor;
|
final Color selectedColor = widget.selectedColor ?? CupertinoTheme.of(context).primaryColor;
|
||||||
if (_selectedColor != selectedColor) {
|
if (_selectedColor != selectedColor) {
|
||||||
changed = true;
|
changed = true;
|
||||||
@ -197,6 +235,13 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
changed = true;
|
changed = true;
|
||||||
_unselectedColor = unselectedColor;
|
_unselectedColor = unselectedColor;
|
||||||
}
|
}
|
||||||
|
final Color selectedDisabledColor = widget.disabledColor ?? selectedColor.withOpacity(0.5);
|
||||||
|
final Color unselectedDisabledColor = widget.disabledColor ?? unselectedColor;
|
||||||
|
if (_selectedDisabledColor != selectedDisabledColor || _unselectedDisabledColor != unselectedDisabledColor) {
|
||||||
|
changed = true;
|
||||||
|
_selectedDisabledColor = selectedDisabledColor;
|
||||||
|
_unselectedDisabledColor = unselectedDisabledColor;
|
||||||
|
}
|
||||||
final Color borderColor = widget.borderColor ?? CupertinoTheme.of(context).primaryColor;
|
final Color borderColor = widget.borderColor ?? CupertinoTheme.of(context).primaryColor;
|
||||||
if (_borderColor != borderColor) {
|
if (_borderColor != borderColor) {
|
||||||
changed = true;
|
changed = true;
|
||||||
@ -302,13 +347,18 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
if (currentKey != _pressedKey) {
|
if (currentKey != _pressedKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentKey != widget.groupValue) {
|
if (!widget.disabledChildren.contains(currentKey)) {
|
||||||
widget.onValueChanged(currentKey);
|
if (currentKey != widget.groupValue) {
|
||||||
|
widget.onValueChanged(currentKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_pressedKey = null;
|
_pressedKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color? getTextColor(int index, T currentKey) {
|
Color? getTextColor(int index, T currentKey) {
|
||||||
|
if (widget.disabledChildren.contains(currentKey)) {
|
||||||
|
return _disabledTextColor;
|
||||||
|
}
|
||||||
if (_selectionControllers[index].isAnimating) {
|
if (_selectionControllers[index].isAnimating) {
|
||||||
return _textColorTween.evaluate(_selectionControllers[index]);
|
return _textColorTween.evaluate(_selectionControllers[index]);
|
||||||
}
|
}
|
||||||
@ -319,6 +369,9 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color? getBackgroundColor(int index, T currentKey) {
|
Color? getBackgroundColor(int index, T currentKey) {
|
||||||
|
if (widget.disabledChildren.contains(currentKey)) {
|
||||||
|
return widget.groupValue == currentKey ? _selectedDisabledColor : _unselectedDisabledColor;
|
||||||
|
}
|
||||||
if (_selectionControllers[index].isAnimating) {
|
if (_selectionControllers[index].isAnimating) {
|
||||||
return _childTweens[index].evaluate(_selectionControllers[index]);
|
return _childTweens[index].evaluate(_selectionControllers[index]);
|
||||||
}
|
}
|
||||||
@ -357,10 +410,10 @@ class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedC
|
|||||||
cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer,
|
cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTapDown: (TapDownDetails event) {
|
onTapDown: widget.disabledChildren.contains(currentKey) ? null : (TapDownDetails event) {
|
||||||
_onTapDown(currentKey);
|
_onTapDown(currentKey);
|
||||||
},
|
},
|
||||||
onTapCancel: _onTapCancel,
|
onTapCancel: widget.disabledChildren.contains(currentKey) ? null : _onTapCancel,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_onTap(currentKey);
|
_onTap(currentKey);
|
||||||
},
|
},
|
||||||
|
@ -1641,4 +1641,123 @@ void main() {
|
|||||||
kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Tap on disabled segment should not change its state', (WidgetTester tester) async {
|
||||||
|
final Map<int, Widget> children = <int, Widget>{
|
||||||
|
0: const Text('Child 1'),
|
||||||
|
1: const Text('Child 2'),
|
||||||
|
2: const Text('Child 3'),
|
||||||
|
};
|
||||||
|
|
||||||
|
final Set<int> disabledChildren = <int>{1};
|
||||||
|
|
||||||
|
int sharedValue = 0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return boilerplate(
|
||||||
|
child: CupertinoSegmentedControl<int>(
|
||||||
|
key: const ValueKey<String>('Segmented Control'),
|
||||||
|
children: children,
|
||||||
|
disabledChildren: disabledChildren,
|
||||||
|
onValueChanged: (int newValue) {
|
||||||
|
setState(() {
|
||||||
|
sharedValue = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
groupValue: sharedValue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(sharedValue, 0);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Child 2'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(sharedValue, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Background color of disabled segment should be different than enabled segment', (WidgetTester tester) async {
|
||||||
|
final Map<int, Widget> children = <int, Widget>{
|
||||||
|
0: const Text('Child 1'),
|
||||||
|
1: const Text('Child 2'),
|
||||||
|
};
|
||||||
|
int sharedValue = 0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return boilerplate(
|
||||||
|
child: CupertinoSegmentedControl<int>(
|
||||||
|
children: children,
|
||||||
|
disabledChildren: const <int>{0},
|
||||||
|
onValueChanged: (int newValue) {
|
||||||
|
setState(() {
|
||||||
|
sharedValue = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
groupValue: sharedValue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Colors are different for disabled and enabled segments in initial state.
|
||||||
|
// By default, the first segment is selected (and also is disabled in this test),
|
||||||
|
// it should have a blue background (selected color) with 50% opacity
|
||||||
|
expect(
|
||||||
|
getBackgroundColor(tester, 0),
|
||||||
|
isSameColorAs(CupertinoColors.systemBlue.withOpacity(0.5)),
|
||||||
|
);
|
||||||
|
expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white));
|
||||||
|
|
||||||
|
// Tap on disabled segment should not change its color
|
||||||
|
await tester.tap(find.text('Child 1'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getBackgroundColor(tester, 0),
|
||||||
|
isSameColorAs(CupertinoColors.systemBlue.withOpacity(0.5)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// When tapping on another enabled segment, the first disabled segment is not selected anymore,
|
||||||
|
// it should have a white background (same to unselected color).
|
||||||
|
await tester.tap(find.text('Child 2'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(getBackgroundColor(tester, 0), isSameColorAs(CupertinoColors.white));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Custom disabled color of disabled segment is showing as desired', (WidgetTester tester) async {
|
||||||
|
final Map<int, Widget> children = <int, Widget>{
|
||||||
|
0: const Text('Child 1'),
|
||||||
|
1: const Text('Child 2'),
|
||||||
|
2: const Text('Child 3'),
|
||||||
|
};
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return boilerplate(
|
||||||
|
child: CupertinoSegmentedControl<int>(
|
||||||
|
children: children,
|
||||||
|
disabledChildren: const <int>{0},
|
||||||
|
onValueChanged: (int newValue) {},
|
||||||
|
disabledColor: CupertinoColors.systemGrey2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getBackgroundColor(tester, 0),
|
||||||
|
isSameColorAs(CupertinoColors.systemGrey2),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user