Add Material 3 `RadioListTile` example and update existing examples (#119716)
* Add Material 3 `RadioListTile` example and update existing examples
* Update examples with `useMaterial3: true` and update example descriptions.
* add a `ColorScheme` colour
diff --git a/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart
new file mode 100644
index 0000000..4080992
--- /dev/null
+++ b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart
@@ -0,0 +1,118 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flutter code sample for custom labeled radio.
+
+import 'package:flutter/gestures.dart';
+
+import 'package:flutter/material.dart';
+
+void main() => runApp(const LabeledRadioApp());
+
+class LabeledRadioApp extends StatelessWidget {
+ const LabeledRadioApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ theme: ThemeData(useMaterial3: true),
+ home: Scaffold(
+ appBar: AppBar(title: const Text('Custom Labeled Radio Sample')),
+ body: const LabeledRadioExample(),
+ ),
+ );
+ }
+}
+
+class LinkedLabelRadio extends StatelessWidget {
+ const LinkedLabelRadio({
+ super.key,
+ required this.label,
+ required this.padding,
+ required this.groupValue,
+ required this.value,
+ required this.onChanged,
+ });
+
+ final String label;
+ final EdgeInsets padding;
+ final bool groupValue;
+ final bool value;
+ final ValueChanged<bool> onChanged;
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: padding,
+ child: Row(
+ children: <Widget>[
+ Radio<bool>(
+ groupValue: groupValue,
+ value: value,
+ onChanged: (bool? newValue) {
+ onChanged(newValue!);
+ },
+ ),
+ RichText(
+ text: TextSpan(
+ text: label,
+ style: TextStyle(
+ color: Theme.of(context).colorScheme.primary,
+ decoration: TextDecoration.underline,
+ ),
+ recognizer: TapGestureRecognizer()
+ ..onTap = () {
+ debugPrint('Label has been tapped.');
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class LabeledRadioExample extends StatefulWidget {
+ const LabeledRadioExample({super.key});
+
+ @override
+ State<LabeledRadioExample> createState() => _LabeledRadioExampleState();
+}
+
+class _LabeledRadioExampleState extends State<LabeledRadioExample> {
+ bool _isRadioSelected = false;
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ LinkedLabelRadio(
+ label: 'First tappable label text',
+ padding: const EdgeInsets.symmetric(horizontal: 5.0),
+ value: true,
+ groupValue: _isRadioSelected,
+ onChanged: (bool newValue) {
+ setState(() {
+ _isRadioSelected = newValue;
+ });
+ },
+ ),
+ LinkedLabelRadio(
+ label: 'Second tappable label text',
+ padding: const EdgeInsets.symmetric(horizontal: 5.0),
+ value: false,
+ groupValue: _isRadioSelected,
+ onChanged: (bool newValue) {
+ setState(() {
+ _isRadioSelected = newValue;
+ });
+ },
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.2.dart b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart
similarity index 79%
rename from examples/api/lib/material/radio_list_tile/radio_list_tile.2.dart
rename to examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart
index ddd85dd..4ca903a 100644
--- a/examples/api/lib/material/radio_list_tile/radio_list_tile.2.dart
+++ b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart
@@ -2,24 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flutter code sample for [RadioListTile].
+// Flutter code sample for custom labeled radio.
import 'package:flutter/material.dart';
-void main() => runApp(const MyApp());
+void main() => runApp(const LabeledRadioApp());
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- static const String _title = 'Flutter Code Sample';
+class LabeledRadioApp extends StatelessWidget {
+ const LabeledRadioApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: _title,
+ theme: ThemeData(useMaterial3: true),
home: Scaffold(
- appBar: AppBar(title: const Text(_title)),
- body: const MyStatefulWidget(),
+ appBar: AppBar(title: const Text('Custom Labeled Radio Sample')),
+ body: const LabeledRadioExample(),
),
);
}
@@ -68,14 +66,14 @@
}
}
-class MyStatefulWidget extends StatefulWidget {
- const MyStatefulWidget({super.key});
+class LabeledRadioExample extends StatefulWidget {
+ const LabeledRadioExample({super.key});
@override
- State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
+ State<LabeledRadioExample> createState() => _LabeledRadioExampleState();
}
-class _MyStatefulWidgetState extends State<MyStatefulWidget> {
+class _LabeledRadioExampleState extends State<LabeledRadioExample> {
bool _isRadioSelected = false;
@override
diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart
index 8924fe7..01ed639 100644
--- a/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart
+++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart
@@ -6,20 +6,18 @@
import 'package:flutter/material.dart';
-void main() => runApp(const MyApp());
+void main() => runApp(const RadioListTileApp());
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- static const String _title = 'Flutter Code Sample';
+class RadioListTileApp extends StatelessWidget {
+ const RadioListTileApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: _title,
+ theme: ThemeData(useMaterial3: true),
home: Scaffold(
- appBar: AppBar(title: const Text(_title)),
- body: const MyStatefulWidget(),
+ appBar: AppBar(title: const Text('RadioListTile Sample')),
+ body: const RadioListTileExample(),
),
);
}
@@ -27,14 +25,14 @@
enum SingingCharacter { lafayette, jefferson }
-class MyStatefulWidget extends StatefulWidget {
- const MyStatefulWidget({super.key});
+class RadioListTileExample extends StatefulWidget {
+ const RadioListTileExample({super.key});
@override
- State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
+ State<RadioListTileExample> createState() => _RadioListTileExampleState();
}
-class _MyStatefulWidgetState extends State<MyStatefulWidget> {
+class _RadioListTileExampleState extends State<RadioListTileExample> {
SingingCharacter? _character = SingingCharacter.lafayette;
@override
diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart
index 4620b47..dc0db0a 100644
--- a/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart
+++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart
@@ -4,113 +4,73 @@
// Flutter code sample for [RadioListTile].
-import 'package:flutter/gestures.dart';
-
import 'package:flutter/material.dart';
-void main() => runApp(const MyApp());
+void main() => runApp(const RadioListTileApp());
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- static const String _title = 'Flutter Code Sample';
+class RadioListTileApp extends StatelessWidget {
+ const RadioListTileApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: _title,
- home: Scaffold(
- appBar: AppBar(title: const Text(_title)),
- body: const MyStatefulWidget(),
- ),
+ theme: ThemeData(useMaterial3: true),
+ home: const RadioListTileExample(),
);
}
}
-class LinkedLabelRadio extends StatelessWidget {
- const LinkedLabelRadio({
- super.key,
- required this.label,
- required this.padding,
- required this.groupValue,
- required this.value,
- required this.onChanged,
- });
+enum Groceries { pickles, tomato, lettuce }
- final String label;
- final EdgeInsets padding;
- final bool groupValue;
- final bool value;
- final ValueChanged<bool> onChanged;
+class RadioListTileExample extends StatefulWidget {
+ const RadioListTileExample({super.key});
@override
- Widget build(BuildContext context) {
- return Padding(
- padding: padding,
- child: Row(
- children: <Widget>[
- Radio<bool>(
- groupValue: groupValue,
- value: value,
- onChanged: (bool? newValue) {
- onChanged(newValue!);
- }),
- RichText(
- text: TextSpan(
- text: label,
- style: const TextStyle(
- color: Colors.blueAccent,
- decoration: TextDecoration.underline,
- ),
- recognizer: TapGestureRecognizer()
- ..onTap = () {
- debugPrint('Label has been tapped.');
- },
- ),
- ),
- ],
- ),
- );
- }
+ State<RadioListTileExample> createState() => _RadioListTileExampleState();
}
-class MyStatefulWidget extends StatefulWidget {
- const MyStatefulWidget({super.key});
-
- @override
- State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
-}
-
-class _MyStatefulWidgetState extends State<MyStatefulWidget> {
- bool _isRadioSelected = false;
+class _RadioListTileExampleState extends State<RadioListTileExample> {
+ Groceries? _groceryItem = Groceries.pickles;
@override
Widget build(BuildContext context) {
return Scaffold(
+ appBar: AppBar(title: const Text('RadioListTile Sample')),
body: Column(
- mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
- LinkedLabelRadio(
- label: 'First tappable label text',
- padding: const EdgeInsets.symmetric(horizontal: 5.0),
- value: true,
- groupValue: _isRadioSelected,
- onChanged: (bool newValue) {
+ RadioListTile<Groceries>(
+ value: Groceries.pickles,
+ groupValue: _groceryItem,
+ onChanged: (Groceries? value) {
setState(() {
- _isRadioSelected = newValue;
+ _groceryItem = value;
});
},
+ title: const Text('Pickles'),
+ subtitle: const Text('Supporting text'),
),
- LinkedLabelRadio(
- label: 'Second tappable label text',
- padding: const EdgeInsets.symmetric(horizontal: 5.0),
- value: false,
- groupValue: _isRadioSelected,
- onChanged: (bool newValue) {
+ RadioListTile<Groceries>(
+ value: Groceries.tomato,
+ groupValue: _groceryItem,
+ onChanged: (Groceries? value) {
setState(() {
- _isRadioSelected = newValue;
+ _groceryItem = value;
});
},
+ title: const Text('Tomato'),
+ subtitle: const Text('Longer supporting text to demonstrate how the text wraps and the radio is centered vertically with the text.'),
+ ),
+ RadioListTile<Groceries>(
+ value: Groceries.lettuce,
+ groupValue: _groceryItem,
+ onChanged: (Groceries? value) {
+ setState(() {
+ _groceryItem = value;
+ });
+ },
+ title: const Text('Lettuce'),
+ subtitle: const Text("Longer supporting text to demonstrate how the text wraps and how setting 'RadioListTile.isThreeLine = true' aligns the radio to the top vertically with the text."),
+ isThreeLine: true,
),
],
),
diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart
index f025260..70ada4f 100644
--- a/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart
+++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart
@@ -6,33 +6,31 @@
import 'package:flutter/material.dart';
-void main() => runApp(const MyApp());
+void main() => runApp(const RadioListTileApp());
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- static const String _title = 'Flutter Code Sample';
+class RadioListTileApp extends StatelessWidget {
+ const RadioListTileApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: _title,
+ theme: ThemeData(useMaterial3: true),
home: Scaffold(
- appBar: AppBar(title: const Text(_title)),
- body: const MyStatefulWidget(),
+ appBar: AppBar(title: const Text('RadioListTile.toggleable Sample')),
+ body: const RadioListTileExample(),
),
);
}
}
-class MyStatefulWidget extends StatefulWidget {
- const MyStatefulWidget({super.key});
+class RadioListTileExample extends StatefulWidget {
+ const RadioListTileExample({super.key});
@override
- State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
+ State<RadioListTileExample> createState() => _RadioListTileExampleState();
}
-class _MyStatefulWidgetState extends State<MyStatefulWidget> {
+class _RadioListTileExampleState extends State<RadioListTileExample> {
int? groupValue;
static const List<String> selections = <String>[
'Hercules Mulligan',
diff --git a/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart b/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart
new file mode 100644
index 0000000..67842b1
--- /dev/null
+++ b/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart
@@ -0,0 +1,43 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_api_samples/material/radio_list_tile/custom_labeled_radio.0.dart' as example;
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('LinkedLabelRadio contains RichText and Radio', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.LabeledRadioApp(),
+ );
+
+ // Label text is in a RichText widget with the correct text.
+ final RichText richText = tester.widget(find.byType(RichText).first);
+ expect(richText.text.toPlainText(), 'First tappable label text');
+
+ // First Radio is initially unchecked.
+ Radio<bool> radio = tester.widget(find.byType(Radio<bool>).first);
+ expect(radio.value, true);
+ expect(radio.groupValue, false);
+
+ // Last Radio is initially checked.
+ radio = tester.widget(find.byType(Radio<bool>).last);
+ expect(radio.value, false);
+ expect(radio.groupValue, false);
+
+ // Tap the first radio.
+ await tester.tap(find.byType(Radio<bool>).first);
+ await tester.pump();
+
+ // First Radio is now checked.
+ radio = tester.widget(find.byType(Radio<bool>).first);
+ expect(radio.value, true);
+ expect(radio.groupValue, true);
+
+ // Last Radio is now unchecked.
+ radio = tester.widget(find.byType(Radio<bool>).last);
+ expect(radio.value, false);
+ expect(radio.groupValue, true);
+ });
+}
diff --git a/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart b/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart
new file mode 100644
index 0000000..087f8d9
--- /dev/null
+++ b/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart
@@ -0,0 +1,39 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_api_samples/material/radio_list_tile/custom_labeled_radio.1.dart' as example;
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('Tapping LabeledRadio toggles the radio', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.LabeledRadioApp(),
+ );
+
+ // First Radio is initially unchecked.
+ Radio<bool> radio = tester.widget(find.byType(Radio<bool>).first);
+ expect(radio.value, true);
+ expect(radio.groupValue, false);
+
+ // Last Radio is initially checked.
+ radio = tester.widget(find.byType(Radio<bool>).last);
+ expect(radio.value, false);
+ expect(radio.groupValue, false);
+
+ // Tap the first labeled radio to toggle the Radio widget.
+ await tester.tap(find.byType(example.LabeledRadio).first);
+ await tester.pumpAndSettle();
+
+ // First Radio is now checked.
+ radio = tester.widget(find.byType(Radio<bool>).first);
+ expect(radio.value, true);
+ expect(radio.groupValue, true);
+
+ // Last Radio is now unchecked.
+ radio = tester.widget(find.byType(Radio<bool>).last);
+ expect(radio.value, false);
+ expect(radio.groupValue, true);
+ });
+}
diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart
new file mode 100644
index 0000000..7da8c3f
--- /dev/null
+++ b/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart
@@ -0,0 +1,38 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_api_samples/material/radio_list_tile/radio_list_tile.0.dart' as example;
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('Can update RadioListTile group value', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.RadioListTileApp(),
+ );
+
+ // Find the number of RadioListTiles.
+ expect(find.byType(RadioListTile<example.SingingCharacter>), findsNWidgets(2));
+
+ // The initial group value is lafayette for the first RadioListTile.
+ RadioListTile<example.SingingCharacter> radioListTile = tester.widget(find.byType(RadioListTile<example.SingingCharacter>).first);
+ expect(radioListTile.groupValue, example.SingingCharacter.lafayette);
+
+ // The initial group value is lafayette for the last RadioListTile.
+ radioListTile = tester.widget(find.byType(RadioListTile<example.SingingCharacter>).last);
+ expect(radioListTile.groupValue, example.SingingCharacter.lafayette);
+
+ // Tap the last RadioListTile to change the group value to jefferson.
+ await tester.tap(find.byType(RadioListTile<example.SingingCharacter>).last);
+ await tester.pump();
+
+ // The group value is now jefferson for the first RadioListTile.
+ radioListTile = tester.widget(find.byType(RadioListTile<example.SingingCharacter>).first);
+ expect(radioListTile.groupValue, example.SingingCharacter.jefferson);
+
+ // The group value is now jefferson for the last RadioListTile.
+ radioListTile = tester.widget(find.byType(RadioListTile<example.SingingCharacter>).last);
+ expect(radioListTile.groupValue, example.SingingCharacter.jefferson);
+ });
+}
diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart
new file mode 100644
index 0000000..2fcf0c6
--- /dev/null
+++ b/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart
@@ -0,0 +1,94 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_api_samples/material/radio_list_tile/radio_list_tile.1.dart' as example;
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('Radio aligns appropriately', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.RadioListTileApp(),
+ );
+
+ expect(find.byType(RadioListTile<example.Groceries>), findsNWidgets(3));
+
+ Offset tileTopLeft = tester.getTopLeft(find.byType(RadioListTile<example.Groceries>).at(0));
+ Offset radioTopLeft = tester.getTopLeft(find.byType(Radio<example.Groceries>).at(0));
+
+ // The radio is centered vertically with the text.
+ expect(radioTopLeft - tileTopLeft, const Offset(16.0, 16.0));
+
+ tileTopLeft = tester.getTopLeft(find.byType(RadioListTile<example.Groceries>).at(1));
+ radioTopLeft = tester.getTopLeft(find.byType(Radio<example.Groceries>).at(1));
+
+ // The radio is centered vertically with the text.
+ expect(radioTopLeft - tileTopLeft, const Offset(16.0, 30.0));
+
+ tileTopLeft = tester.getTopLeft(find.byType(RadioListTile<example.Groceries>).at(2));
+ radioTopLeft = tester.getTopLeft(find.byType(Radio<example.Groceries>).at(2));
+
+ // The radio is aligned to the top vertically with the text.
+ expect(radioTopLeft - tileTopLeft, const Offset(16.0, 8.0));
+ });
+
+ testWidgets('Radios can be checked', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.RadioListTileApp(),
+ );
+
+ expect(find.byType(RadioListTile<example.Groceries>), findsNWidgets(3));
+ final Finder radioListTile = find.byType(RadioListTile<example.Groceries>);
+
+ // Initially the first radio is checked.
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(0)).groupValue,
+ example.Groceries.pickles,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(1)).groupValue,
+ example.Groceries.pickles,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(2)).groupValue,
+ example.Groceries.pickles,
+ );
+
+ // Tap the second radio.
+ await tester.tap(find.byType(Radio<example.Groceries>).at(1));
+ await tester.pumpAndSettle();
+
+ // The second radio is checked.
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(0)).groupValue,
+ example.Groceries.tomato,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(1)).groupValue,
+ example.Groceries.tomato,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(2)).groupValue,
+ example.Groceries.tomato,
+ );
+
+ // Tap the third radio.
+ await tester.tap(find.byType(Radio<example.Groceries>).at(2));
+ await tester.pumpAndSettle();
+
+ // The third radio is checked.
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(0)).groupValue,
+ example.Groceries.lettuce,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(1)).groupValue,
+ example.Groceries.lettuce,
+ );
+ expect(
+ tester.widget<RadioListTile<example.Groceries>>(radioListTile.at(2)).groupValue,
+ example.Groceries.lettuce,
+ );
+ });
+}
diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart
new file mode 100644
index 0000000..f88b276
--- /dev/null
+++ b/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart
@@ -0,0 +1,38 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_api_samples/material/radio_list_tile/radio_list_tile.toggleable.0.dart' as example;
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('RadioListTile is toggleable', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const example.RadioListTileApp(),
+ );
+
+ // Initially the third radio button is not selected.
+ Radio<int> radio = tester.widget(find.byType(Radio<int>).at(2));
+ expect(radio.value, 2);
+ expect(radio.groupValue, null);
+
+ // Tap the third radio button.
+ await tester.tap(find.text('Philip Schuyler'));
+ await tester.pumpAndSettle();
+
+ // The third radio button is now selected.
+ radio = tester.widget(find.byType(Radio<int>).at(2));
+ expect(radio.value, 2);
+ expect(radio.groupValue, 2);
+
+ // Tap the third radio button again.
+ await tester.tap(find.text('Philip Schuyler'));
+ await tester.pumpAndSettle();
+
+ // The third radio button is now unselected.
+ radio = tester.widget(find.byType(Radio<int>).at(2));
+ expect(radio.value, 2);
+ expect(radio.groupValue, null);
+ });
+}
diff --git a/packages/flutter/lib/src/material/radio_list_tile.dart b/packages/flutter/lib/src/material/radio_list_tile.dart
index 31f6f16..756e983 100644
--- a/packages/flutter/lib/src/material/radio_list_tile.dart
+++ b/packages/flutter/lib/src/material/radio_list_tile.dart
@@ -86,6 +86,13 @@
/// ** See code in examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart **
/// {@end-tool}
///
+/// {@tool dartpad}
+/// This sample demonstrates how [RadioListTile] positions the radio widget
+/// relative to the text in different configurations.
+///
+/// ** See code in examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart **
+/// {@end-tool}
+///
/// ## Semantics in RadioListTile
///
/// Since the entirety of the RadioListTile is interactive, it should represent
@@ -110,7 +117,7 @@
/// LinkedLabelRadio, that includes an interactive [RichText] widget that
/// handles tap gestures.
///
-/// ** See code in examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart **
+/// ** See code in examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart **
/// {@end-tool}
///
/// ## RadioListTile isn't exactly what I want
@@ -126,7 +133,7 @@
/// Here is an example of a custom LabeledRadio widget, but you can easily
/// make your own configurable widget.
///
-/// ** See code in examples/api/lib/material/radio_list_tile/radio_list_tile.2.dart **
+/// ** See code in examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart **
/// {@end-tool}
///
/// See also: