Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/toggle_switch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,16 @@ class _ToggleSwitchState extends State<ToggleSwitch>
newIndex = null;
}

// When the widget manages its own state and doubleTapDisable is false,
// skip onToggle if the tapped switch is already active — selection unchanged.
if (widget.changeOnTap &&
!widget.doubleTapDisable &&
widget.initialLabelIndex == newIndex) {
return;
}

final cancel = await widget.cancelToggle?.call(newIndex) ?? false;
Comment thread
Vasusn marked this conversation as resolved.
if (cancel) {
if (!mounted || cancel) {
return;
}

Expand Down
76 changes: 76 additions & 0 deletions test/toggle_switch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,80 @@ void main() {
expect(helloTextFinder, findsOneWidget);
expect(flutterTextFinder, findsOneWidget);
});

// onToggle should NOT be called when tapping the already-active switch
// when changeOnTap is true and doubleTapDisable is false.
testWidgets('onToggle is not triggered when tapping already-active switch',
(WidgetTester tester) async {
int toggleCallCount = 0;

await tester.pumpWidget(
MediaQuery(
data: MediaQueryData(size: const Size(800, 600)),
child: MaterialApp(
home: Scaffold(
body: Center(
child: ToggleSwitch(
totalSwitches: 3,
labels: ['A', 'B', 'C'],
initialLabelIndex: 0,
onToggle: (index) {
toggleCallCount++;
},
),
),
),
),
),
);

// Tap on the already-active switch (label 'A', index 0).
await tester.tap(find.text('A'));
await tester.pumpAndSettle();

// onToggle should NOT have been called.
expect(toggleCallCount, equals(0));

// Tap on a different switch (label 'B', index 1) — should fire onToggle.
await tester.tap(find.text('B'));
await tester.pumpAndSettle();

expect(toggleCallCount, equals(1));
});

// When doubleTapDisable is true, tapping the active switch should fire
// onToggle with null (deselect), not be swallowed.
testWidgets(
'onToggle fires with null when doubleTapDisable is true and active switch is tapped',
(WidgetTester tester) async {
int? lastToggledIndex = -1;

await tester.pumpWidget(
MediaQuery(
data: MediaQueryData(size: const Size(800, 600)),
child: MaterialApp(
home: Scaffold(
body: Center(
child: ToggleSwitch(
totalSwitches: 3,
labels: ['A', 'B', 'C'],
initialLabelIndex: 0,
doubleTapDisable: true,
onToggle: (index) {
lastToggledIndex = index;
},
),
),
),
),
),
);

// Tap on the already-active switch (label 'A', index 0).
await tester.tap(find.text('A'));
await tester.pumpAndSettle();

// onToggle should be called with null (deselect).
expect(lastToggledIndex, isNull);
});
}