diff --git a/packages/flutter/lib/src/material/segmented_button.dart b/packages/flutter/lib/src/material/segmented_button.dart index dd698db250..01b52295ac 100644 --- a/packages/flutter/lib/src/material/segmented_button.dart +++ b/packages/flutter/lib/src/material/segmented_button.dart @@ -17,6 +17,7 @@ import 'segmented_button_theme.dart'; import 'text_button.dart'; import 'text_button_theme.dart'; import 'theme.dart'; +import 'tooltip.dart'; /// Data describing a segment of a [SegmentedButton]. class ButtonSegment { @@ -27,6 +28,7 @@ class ButtonSegment { required this.value, this.icon, this.label, + this.tooltip, this.enabled = true, }) : assert(icon != null || label != null); @@ -41,6 +43,9 @@ class ButtonSegment { /// Optional label displayed in the segment. final Widget? label; + /// Optional tooltip for the segment + final String? tooltip; + /// Determines if the segment is available for selection. final bool enabled; } @@ -335,11 +340,18 @@ class SegmentedButton extends StatelessWidget { child: label, ); + final Widget buttonWithTooltip = (segment.tooltip != null) + ? Tooltip( + message: segment.tooltip, + child: button, + ) + : button; + return MergeSemantics( child: Semantics( checked: segmentSelected, inMutuallyExclusiveGroup: multiSelectionEnabled ? null : true, - child: button, + child: buttonWithTooltip, ), ); } diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index ff863a860c..cb785b3217 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -533,4 +533,59 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(overlayColor(), paints..rect()..rect(color: theme.colorScheme.onSurface.withOpacity(0.12))); expect(material.textStyle?.color, theme.colorScheme.onSurface); }); + + testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: SegmentedButton( + segments: const >[ + ButtonSegment(value: 1, label: Text('1')), + ButtonSegment(value: 2, label: Text('2')), + ButtonSegment(value: 3, label: Text('3'), enabled: false), + ], + selected: const {2}, + onSelectionChanged: (Set selected) { }, + ), + ), + ), + ), + ); + + expect(find.byType(Tooltip), findsNothing); + }); + + testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: SegmentedButton( + segments: const >[ + ButtonSegment(value: 1, label: Text('1')), + ButtonSegment(value: 2, label: Text('2'), tooltip: 't2'), + ButtonSegment( + value: 3, + label: Text('3'), + tooltip: 't3', + enabled: false, + ), + ], + selected: const {2}, + onSelectionChanged: (Set selected) { }, + ), + ), + ), + ), + ); + + expect(find.byType(Tooltip), findsNWidgets(2)); + expect(find.byTooltip('t2'), findsOneWidget); + expect(find.byTooltip('t3'), findsOneWidget); + }); }