Skip to content

Commit 4ffc41a

Browse files
authored
ToggleButtons: Add interactive example (#100124)
1 parent 99769b0 commit 4ffc41a

3 files changed

Lines changed: 282 additions & 0 deletions

File tree

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flutter code sample for ToggleButtons
6+
7+
import 'package:flutter/material.dart';
8+
9+
const List<Widget> fruits = <Widget>[
10+
Text('Apple'),
11+
Text('Banana'),
12+
Text('Orange')
13+
];
14+
15+
const List<Widget> vegetables = <Widget>[
16+
Text('Tomatoes'),
17+
Text('Potatoes'),
18+
Text('Carrots')
19+
];
20+
21+
const List<Widget> icons = <Widget>[
22+
Icon(Icons.sunny),
23+
Icon(Icons.cloud),
24+
Icon(Icons.ac_unit),
25+
];
26+
27+
void main() => runApp(const MyApp());
28+
29+
class MyApp extends StatelessWidget {
30+
const MyApp({Key? key}) : super(key: key);
31+
32+
static const String _title = 'ToggleButtons Sample';
33+
34+
@override
35+
Widget build(BuildContext context) {
36+
return const MaterialApp(
37+
title: _title,
38+
home: ToggleButtonsSample(title: _title),
39+
);
40+
}
41+
}
42+
43+
class ToggleButtonsSample extends StatefulWidget {
44+
const ToggleButtonsSample({Key? key, required this.title}) : super(key: key);
45+
46+
final String title;
47+
48+
@override
49+
State<ToggleButtonsSample> createState() => _ToggleButtonsSampleState();
50+
}
51+
52+
class _ToggleButtonsSampleState extends State<ToggleButtonsSample> {
53+
final List<bool> _selectedFruits = <bool>[true, false, false];
54+
final List<bool> _selectedVegetables = <bool>[false, true, false];
55+
final List<bool> _selectedWeather = <bool>[false, false, true];
56+
bool vertical = false;
57+
58+
@override
59+
Widget build(BuildContext context) {
60+
final ThemeData theme = Theme.of(context);
61+
62+
return Scaffold(
63+
appBar: AppBar(title: Text(widget.title)),
64+
body: Center(
65+
child: SingleChildScrollView(
66+
child: Column(
67+
mainAxisSize: MainAxisSize.min,
68+
mainAxisAlignment: MainAxisAlignment.center,
69+
children: <Widget>[
70+
// ToggleButtons with a single selection.
71+
Text('Single-select', style: theme.textTheme.subtitle2),
72+
const SizedBox(height: 5),
73+
ToggleButtons(
74+
direction: vertical ? Axis.vertical : Axis.horizontal,
75+
onPressed: (int index) {
76+
setState(() {
77+
// The button that is tapped is set to true, and the others to false.
78+
for (int i = 0; i < _selectedFruits.length; i++) {
79+
_selectedFruits[i] = i == index;
80+
}
81+
});
82+
},
83+
borderRadius: const BorderRadius.all(Radius.circular(8)),
84+
selectedBorderColor: Colors.red[700],
85+
selectedColor: Colors.white,
86+
fillColor: Colors.red[200],
87+
color: Colors.red[400],
88+
constraints: const BoxConstraints(
89+
minHeight: 40.0,
90+
minWidth: 80.0,
91+
),
92+
isSelected: _selectedFruits,
93+
children: fruits,
94+
),
95+
const SizedBox(height: 20),
96+
// ToggleButtons with a multiple selection.
97+
Text('Multi-select', style: theme.textTheme.subtitle2),
98+
const SizedBox(height: 5),
99+
ToggleButtons(
100+
direction: vertical ? Axis.vertical : Axis.horizontal,
101+
onPressed: (int index) {
102+
// All buttons are selectable.
103+
setState(() {
104+
_selectedVegetables[index] =
105+
!_selectedVegetables[index];
106+
});
107+
},
108+
borderRadius: const BorderRadius.all(Radius.circular(8)),
109+
selectedBorderColor: Colors.green[700],
110+
selectedColor: Colors.white,
111+
fillColor: Colors.green[200],
112+
color: Colors.green[400],
113+
constraints: const BoxConstraints(
114+
minHeight: 40.0,
115+
minWidth: 80.0,
116+
),
117+
isSelected: _selectedVegetables,
118+
children: vegetables,
119+
),
120+
const SizedBox(height: 20),
121+
// ToggleButtons with icons only.
122+
Text('Icon-only', style: theme.textTheme.subtitle2),
123+
const SizedBox(height: 5),
124+
ToggleButtons(
125+
direction: vertical ? Axis.vertical : Axis.horizontal,
126+
onPressed: (int index) {
127+
setState(() {
128+
// The button that is tapped is set to true, and the others to false.
129+
for (int i = 0; i < _selectedWeather.length; i++) {
130+
_selectedWeather[i] = i == index;
131+
}
132+
});
133+
},
134+
borderRadius: const BorderRadius.all(Radius.circular(8)),
135+
selectedBorderColor: Colors.blue[700],
136+
selectedColor: Colors.white,
137+
fillColor: Colors.blue[200],
138+
color: Colors.blue[400],
139+
isSelected: _selectedWeather,
140+
children: icons,
141+
),
142+
],
143+
),
144+
),
145+
),
146+
floatingActionButton: FloatingActionButton.extended(
147+
onPressed: () {
148+
setState(() {
149+
// When the button is pressed, ToggleButtons direction is changed.
150+
vertical = !vertical;
151+
});
152+
},
153+
icon: const Icon(Icons.screen_rotation_outlined),
154+
label: Text(vertical ? 'Horizontal' : 'Vertical'),
155+
),
156+
);
157+
}
158+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter_api_samples/material/toggle_buttons/toggle_buttons.0.dart' as example;
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
void main() {
10+
11+
testWidgets('Single-select ToggleButtons', (WidgetTester tester) async {
12+
TextButton findButton(String text) {
13+
return tester.widget<TextButton>(find.widgetWithText(TextButton, text));
14+
}
15+
await tester.pumpWidget(
16+
const MaterialApp(
17+
home: Scaffold(
18+
body: example.MyApp(),
19+
),
20+
),
21+
);
22+
23+
TextButton firstButton = findButton('Apple');
24+
TextButton secondButton = findButton('Banana');
25+
TextButton thirdButton = findButton('Orange');
26+
27+
/// First button is selected.
28+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0xffef9a9a));
29+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
30+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
31+
32+
/// Tap on second button.
33+
await tester.tap(find.widgetWithText(TextButton, 'Banana'));
34+
await tester.pumpAndSettle();
35+
36+
firstButton = findButton('Apple');
37+
secondButton = findButton('Banana');
38+
thirdButton = findButton('Orange');
39+
40+
/// Only second button is selected.
41+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
42+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0xffef9a9a));
43+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
44+
});
45+
46+
testWidgets('Multi-select ToggleButtons', (WidgetTester tester) async {
47+
TextButton findButton(String text) {
48+
return tester.widget<TextButton>(find.widgetWithText(TextButton, text));
49+
}
50+
await tester.pumpWidget(
51+
const MaterialApp(
52+
home: Scaffold(
53+
body: example.MyApp(),
54+
),
55+
),
56+
);
57+
58+
TextButton firstButton = findButton('Tomatoes');
59+
TextButton secondButton = findButton('Potatoes');
60+
TextButton thirdButton = findButton('Carrots');
61+
62+
/// Second button is selected.
63+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
64+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0xffa5d6a7));
65+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
66+
67+
/// Tap on other two buttons.
68+
await tester.tap(find.widgetWithText(TextButton, 'Tomatoes'));
69+
await tester.tap(find.widgetWithText(TextButton, 'Carrots'));
70+
await tester.pumpAndSettle();
71+
72+
firstButton = findButton('Tomatoes');
73+
secondButton = findButton('Potatoes');
74+
thirdButton = findButton('Carrots');
75+
76+
/// All buttons are selected.
77+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0xffa5d6a7));
78+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0xffa5d6a7));
79+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0xffa5d6a7));
80+
});
81+
82+
testWidgets('Icon-only ToggleButtons', (WidgetTester tester) async {
83+
TextButton findButton(IconData iconData) {
84+
return tester.widget<TextButton>(find.widgetWithIcon(TextButton, iconData));
85+
}
86+
await tester.pumpWidget(
87+
const MaterialApp(
88+
home: Scaffold(
89+
body: example.MyApp(),
90+
),
91+
),
92+
);
93+
94+
TextButton firstButton = findButton(Icons.sunny);
95+
TextButton secondButton = findButton(Icons.cloud);
96+
TextButton thirdButton = findButton(Icons.ac_unit);
97+
98+
/// Third button is selected.
99+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
100+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
101+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0xff90caf9));
102+
103+
/// Tap on the first button.
104+
await tester.tap(find.widgetWithIcon(TextButton, Icons.sunny));
105+
await tester.pumpAndSettle();
106+
107+
firstButton = findButton(Icons.sunny);
108+
secondButton = findButton(Icons.cloud);
109+
thirdButton = findButton(Icons.ac_unit);
110+
111+
/// First button os selected.
112+
expect(firstButton.style!.backgroundColor!.resolve(enabled), const Color(0xff90caf9));
113+
expect(secondButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
114+
expect(thirdButton.style!.backgroundColor!.resolve(enabled), const Color(0x00ffffff));
115+
});
116+
}
117+
118+
Set<MaterialState> enabled = <MaterialState>{ };

packages/flutter/lib/src/material/toggle_buttons.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ import 'toggle_buttons_theme.dart';
2828
///
2929
/// {@youtube 560 315 https://www.youtube.com/watch?v=kVEguaQWGAY}
3030
///
31+
/// {@tool dartpad}
32+
/// This example showcase [ToggleButtons] in various configurations.
33+
///
34+
/// ** See code in examples/api/lib/material/toggle_buttons/toggle_buttons.0.dart **
35+
/// {@end-tool}
36+
///
3137
/// ## Customizing toggle buttons
3238
/// Each toggle's behavior can be configured by the [onPressed] callback, which
3339
/// can update the [isSelected] list however it wants to.

0 commit comments

Comments
 (0)