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:
@@ -37,6 +37,9 @@ class SegmentedControlExample extends StatefulWidget {
|
||||
|
||||
class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
||||
Sky _selectedSegment = Sky.midnight;
|
||||
bool _toggleOne = false;
|
||||
bool _toggleAll = true;
|
||||
Set<Sky> _disabledChildren = <Sky>{};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -45,6 +48,7 @@ class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
// This Cupertino segmented control has the enum "Sky" as the type.
|
||||
middle: CupertinoSegmentedControl<Sky>(
|
||||
disabledChildren: _disabledChildren,
|
||||
selectedColor: skyColors[_selectedSegment],
|
||||
// Provide horizontal padding around the children.
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
@@ -73,9 +77,60 @@ class _SegmentedControlExampleState extends State<SegmentedControlExample> {
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Selected Segment: ${_selectedSegment.name}',
|
||||
style: const TextStyle(color: CupertinoColors.white),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
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
|
||||
// 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_test/flutter_test.dart';
|
||||
|
||||
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 {
|
||||
await tester.pumpWidget(
|
||||
const example.SegmentedControlApp(),
|
||||
@@ -18,4 +51,50 @@ void main() {
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user