Unverified Commit a0ed52ca authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

Add Doc Samples For CheckboxListTile, RadioListTile and SwitchListTile (#32703)

* Moved Radio documentation line to be above sample

* Added LabeledRadio sample

* Add LabeledCheckbox sample

* Add LabeledSwitch sample

* Added LinkedLabelRadio sample to RadioListTile

* Added LinkedLabelCheckbox sample to CheckboxListTile

* Added LinkedLabelSwitch sample to SwitchListTile

* Added reference to Semantics docs

* Improve simple SwitchListTile, RadioListTile and CheckboxListTile samples

* Added assets to all SwitchListTile, RadioListTile and CheckboxListTile samples
parent 95eed876
...@@ -37,7 +37,9 @@ import 'theme_data.dart'; ...@@ -37,7 +37,9 @@ import 'theme_data.dart';
/// To show the [CheckboxListTile] as disabled, pass null as the [onChanged] /// To show the [CheckboxListTile] as disabled, pass null as the [onChanged]
/// callback. /// callback.
/// ///
/// {@tool sample} /// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![CheckboxListTile sample](https://flutter.github.io/assets-for-api-docs/assets/material/checkbox_list_tile.png)
/// ///
/// This widget shows a checkbox that, when checked, slows down all animations /// This widget shows a checkbox that, when checked, slows down all animations
/// (including the animation of the checkbox itself getting checked!). /// (including the animation of the checkbox itself getting checked!).
...@@ -45,15 +47,196 @@ import 'theme_data.dart'; ...@@ -45,15 +47,196 @@ import 'theme_data.dart';
/// This sample requires that you also import 'package:flutter/scheduler.dart', /// This sample requires that you also import 'package:flutter/scheduler.dart',
/// so that you can reference [timeDilation]. /// so that you can reference [timeDilation].
/// ///
/// ```dart imports
/// import 'package:flutter/scheduler.dart' show timeDilation;
/// ```
/// ```dart /// ```dart
/// CheckboxListTile( /// @override
/// title: const Text('Animate Slowly'), /// Widget build(BuildContext context) {
/// value: timeDilation != 1.0, /// return Center(
/// onChanged: (bool value) { /// child: CheckboxListTile(
/// setState(() { timeDilation = value ? 20.0 : 1.0; }); /// title: const Text('Animate Slowly'),
/// }, /// value: timeDilation != 1.0,
/// secondary: const Icon(Icons.hourglass_empty), /// onChanged: (bool value) {
/// ) /// setState(() { timeDilation = value ? 10.0 : 1.0; });
/// },
/// secondary: const Icon(Icons.hourglass_empty),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// ## Semantics in CheckboxListTile
///
/// Since the entirety of the CheckboxListTile is interactive, it should represent
/// itself as a single interactive entity.
///
/// To do so, a CheckboxListTile widget wraps its children with a [MergeSemantics]
/// widget. [MergeSemantics] will attempt to merge its descendant [Semantics]
/// nodes into one node in the semantics tree. Therefore, CheckboxListTile will
/// throw an error if any of its children requires its own [Semantics] node.
///
/// For example, you cannot nest a [RichText] widget as a descendant of
/// CheckboxListTile. [RichText] has an embedded gesture recognizer that
/// requires its own [Semantics] node, which directly conflicts with
/// CheckboxListTile's desire to merge all its descendants' semantic nodes
/// into one. Therefore, it may be necessary to create a custom radio tile
/// widget to accommodate similar use cases.
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Checkbox list tile semantics sample](https://flutter.github.io/assets-for-api-docs/assets/material/checkbox_list_tile_semantics.png)
///
/// Here is an example of a custom labeled checkbox widget, called
/// LinkedLabelCheckbox, that includes an interactive [RichText] widget that
/// handles tap gestures.
///
/// ```dart imports
/// import 'package:flutter/gestures.dart';
/// ```
/// ```dart preamble
/// class LinkedLabelCheckbox extends StatelessWidget {
/// const LinkedLabelCheckbox({
/// this.label,
/// this.padding,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool value;
/// final Function onChanged;
///
/// @override
/// Widget build(BuildContext context) {
/// return Padding(
/// padding: padding,
/// child: Row(
/// children: <Widget>[
/// Expanded(
/// child: RichText(
/// text: TextSpan(
/// text: label,
/// style: TextStyle(
/// color: Colors.blueAccent,
/// decoration: TextDecoration.underline,
/// ),
/// recognizer: TapGestureRecognizer()
/// ..onTap = () {
/// print('Label has been tapped.');
/// },
/// ),
/// ),
/// ),
/// Checkbox(
/// value: value,
/// onChanged: (bool newValue) {
/// onChanged(newValue);
/// },
/// ),
/// ],
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Center(
/// child: LinkedLabelCheckbox(
/// label: 'Linked, tappable label text',
/// padding: const EdgeInsets.symmetric(horizontal: 20.0),
/// value: _isSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isSelected = newValue;
/// });
/// },
/// ),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// ## CheckboxListTile isn't exactly what I want
///
/// If the way CheckboxListTile pads and positions its elements isn't quite
/// what you're looking for, you can create custom labeled checkbox widgets by
/// combining [Checkbox] with other widgets, such as [Text], [Padding] and
/// [InkWell].
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Custom checkbox list tile sample](https://flutter.github.io/assets-for-api-docs/assets/material/checkbox_list_tile_custom.png)
///
/// Here is an example of a custom LabeledCheckbox widget, but you can easily
/// make your own configurable widget.
///
/// ```dart preamble
/// class LabeledCheckbox extends StatelessWidget {
/// const LabeledCheckbox({
/// this.label,
/// this.padding,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool value;
/// final Function onChanged;
///
/// @override
/// Widget build(BuildContext context) {
/// return InkWell(
/// onTap: () {
/// onChanged(!value);
/// },
/// child: Padding(
/// padding: padding,
/// child: Row(
/// children: <Widget>[
/// Expanded(child: Text(label)),
/// Checkbox(
/// value: value,
/// onChanged: (bool newValue) {
/// onChanged(newValue);
/// },
/// ),
/// ],
/// ),
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Center(
/// child: LabeledCheckbox(
/// label: 'This is the label text',
/// padding: const EdgeInsets.symmetric(horizontal: 20.0),
/// value: _isSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isSelected = newValue;
/// });
/// },
/// ),
/// ),
/// );
/// }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
/// ///
......
...@@ -42,6 +42,8 @@ const double _kInnerRadius = 4.5; ...@@ -42,6 +42,8 @@ const double _kInnerRadius = 4.5;
/// This causes the buttons to rebuild with the updated `groupValue`, and /// This causes the buttons to rebuild with the updated `groupValue`, and
/// therefore the selection of the second button. /// therefore the selection of the second button.
/// ///
/// Requires one of its ancestors to be a [Material] widget.
///
/// ```dart preamble /// ```dart preamble
/// enum SingingCharacter { lafayette, jefferson } /// enum SingingCharacter { lafayette, jefferson }
/// ``` /// ```
...@@ -80,8 +82,6 @@ const double _kInnerRadius = 4.5; ...@@ -80,8 +82,6 @@ const double _kInnerRadius = 4.5;
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
/// ///
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also: /// See also:
/// ///
/// * [RadioListTile], which combines this widget with a [ListTile] so that /// * [RadioListTile], which combines this widget with a [ListTile] so that
......
...@@ -40,35 +40,246 @@ import 'theme_data.dart'; ...@@ -40,35 +40,246 @@ import 'theme_data.dart';
/// To show the [RadioListTile] as disabled, pass null as the [onChanged] /// To show the [RadioListTile] as disabled, pass null as the [onChanged]
/// callback. /// callback.
/// ///
/// {@tool sample} /// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![RadioListTile sample](https://flutter.github.io/assets-for-api-docs/assets/material/radio_list_tile.png)
/// ///
/// This widget shows a pair of radio buttons that control the `_character` /// This widget shows a pair of radio buttons that control the `_character`
/// field. The field is of the type `SingingCharacter`, an enum. /// field. The field is of the type `SingingCharacter`, an enum.
/// ///
/// ```dart /// ```dart preamble
/// // At the top level:
/// enum SingingCharacter { lafayette, jefferson } /// enum SingingCharacter { lafayette, jefferson }
/// /// ```
/// // In the State of a stateful widget: /// ```dart
/// SingingCharacter _character = SingingCharacter.lafayette; /// SingingCharacter _character = SingingCharacter.lafayette;
/// ///
/// // In the build function of that State: /// @override
/// Column( /// Widget build(BuildContext context) {
/// children: <Widget>[ /// return Column(
/// RadioListTile<SingingCharacter>( /// children: <Widget>[
/// title: const Text('Lafayette'), /// RadioListTile<SingingCharacter>(
/// value: SingingCharacter.lafayette, /// title: const Text('Lafayette'),
/// groupValue: _character, /// value: SingingCharacter.lafayette,
/// onChanged: (SingingCharacter value) { setState(() { _character = value; }); }, /// groupValue: _character,
/// onChanged: (SingingCharacter value) { setState(() { _character = value; }); },
/// ),
/// RadioListTile<SingingCharacter>(
/// title: const Text('Thomas Jefferson'),
/// value: SingingCharacter.jefferson,
/// groupValue: _character,
/// onChanged: (SingingCharacter value) { setState(() { _character = value; }); },
/// ),
/// ],
/// );
/// }
/// ```
/// {@end-tool}
///
/// ## Semantics in RadioListTile
///
/// Since the entirety of the RadioListTile is interactive, it should represent
/// itself as a single interactive entity.
///
/// To do so, a RadioListTile widget wraps its children with a [MergeSemantics]
/// widget. [MergeSemantics] will attempt to merge its descendant [Semantics]
/// nodes into one node in the semantics tree. Therefore, RadioListTile will
/// throw an error if any of its children requires its own [Semantics] node.
///
/// For example, you cannot nest a [RichText] widget as a descendant of
/// RadioListTile. [RichText] has an embedded gesture recognizer that
/// requires its own [Semantics] node, which directly conflicts with
/// RadioListTile's desire to merge all its descendants' semantic nodes
/// into one. Therefore, it may be necessary to create a custom radio tile
/// widget to accommodate similar use cases.
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Radio list tile semantics sample](https://flutter.github.io/assets-for-api-docs/assets/material/radio_list_tile_semantics.png)
///
/// Here is an example of a custom labeled radio widget, called
/// LinkedLabelRadio, that includes an interactive [RichText] widget that
/// handles tap gestures.
///
/// ```dart imports
/// import 'package:flutter/gestures.dart';
/// ```
/// ```dart preamble
/// class LinkedLabelRadio extends StatelessWidget {
/// const LinkedLabelRadio({
/// this.label,
/// this.padding,
/// this.groupValue,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool groupValue;
/// final bool value;
/// final Function 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: Colors.blueAccent,
/// decoration: TextDecoration.underline,
/// ),
/// recognizer: TapGestureRecognizer()
/// ..onTap = () {
/// print('Label has been tapped.');
/// },
/// ),
/// ),
/// ],
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isRadioSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// LinkedLabelRadio(
/// label: 'First tappable label text',
/// padding: EdgeInsets.symmetric(horizontal: 5.0),
/// value: true,
/// groupValue: _isRadioSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isRadioSelected = newValue;
/// });
/// },
/// ),
/// LinkedLabelRadio(
/// label: 'Second tappable label text',
/// padding: EdgeInsets.symmetric(horizontal: 5.0),
/// value: false,
/// groupValue: _isRadioSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isRadioSelected = newValue;
/// });
/// },
/// ),
/// ],
/// ), /// ),
/// RadioListTile<SingingCharacter>( /// );
/// title: const Text('Thomas Jefferson'), /// }
/// value: SingingCharacter.jefferson, /// ```
/// groupValue: _character, /// {@end-tool}
/// onChanged: (SingingCharacter value) { setState(() { _character = value; }); }, ///
/// ## RadioListTile isn't exactly what I want
///
/// If the way RadioListTile pads and positions its elements isn't quite what
/// you're looking for, you can create custom labeled radio widgets by
/// combining [Radio] with other widgets, such as [Text], [Padding] and
/// [InkWell].
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Custom radio list tile sample](https://flutter.github.io/assets-for-api-docs/assets/material/radio_list_tile_custom.png)
///
/// Here is an example of a custom LabeledRadio widget, but you can easily
/// make your own configurable widget.
///
/// ```dart preamble
/// class LabeledRadio extends StatelessWidget {
/// const LabeledRadio({
/// this.label,
/// this.padding,
/// this.groupValue,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool groupValue;
/// final bool value;
/// final Function onChanged;
///
/// @override
/// Widget build(BuildContext context) {
/// return InkWell(
/// onTap: () {
/// if (value != groupValue)
/// onChanged(value);
/// },
/// child: Padding(
/// padding: padding,
/// child: Row(
/// children: <Widget>[
/// Radio<bool>(
/// groupValue: groupValue,
/// value: value,
/// onChanged: (bool newValue) {
/// onChanged(newValue);
/// },
/// ),
/// Text(label),
/// ],
/// ),
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isRadioSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <LabeledRadio>[
/// LabeledRadio(
/// label: 'This is the first label text',
/// padding: const EdgeInsets.symmetric(horizontal: 5.0),
/// value: true,
/// groupValue: _isRadioSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isRadioSelected = newValue;
/// });
/// },
/// ),
/// LabeledRadio(
/// label: 'This is the second label text',
/// padding: const EdgeInsets.symmetric(horizontal: 5.0),
/// value: false,
/// groupValue: _isRadioSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isRadioSelected = newValue;
/// });
/// },
/// ),
/// ],
/// ), /// ),
/// ], /// );
/// ) /// }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
/// ///
......
...@@ -46,7 +46,9 @@ enum _SwitchListTileType { material, adaptive } ...@@ -46,7 +46,9 @@ enum _SwitchListTileType { material, adaptive }
/// To show the [SwitchListTile] as disabled, pass null as the [onChanged] /// To show the [SwitchListTile] as disabled, pass null as the [onChanged]
/// callback. /// callback.
/// ///
/// {@tool sample --template=stateful_widget_scaffold} /// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![SwitchListTile sample](https://flutter.github.io/assets-for-api-docs/assets/material/switch_list_tile.png)
/// ///
/// This widget shows a switch that, when toggled, changes the state of a [bool] /// This widget shows a switch that, when toggled, changes the state of a [bool]
/// member field called `_lights`. /// member field called `_lights`.
...@@ -54,6 +56,7 @@ enum _SwitchListTileType { material, adaptive } ...@@ -54,6 +56,7 @@ enum _SwitchListTileType { material, adaptive }
/// ```dart /// ```dart
/// bool _lights = false; /// bool _lights = false;
/// ///
/// @override
/// Widget build(BuildContext context) { /// Widget build(BuildContext context) {
/// return Center( /// return Center(
/// child: SwitchListTile( /// child: SwitchListTile(
...@@ -67,6 +70,181 @@ enum _SwitchListTileType { material, adaptive } ...@@ -67,6 +70,181 @@ enum _SwitchListTileType { material, adaptive }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
/// ///
/// ## Semantics in SwitchListTile
///
/// Since the entirety of the SwitchListTile is interactive, it should represent
/// itself as a single interactive entity.
///
/// To do so, a SwitchListTile widget wraps its children with a [MergeSemantics]
/// widget. [MergeSemantics] will attempt to merge its descendant [Semantics]
/// nodes into one node in the semantics tree. Therefore, SwitchListTile will
/// throw an error if any of its children requires its own [Semantics] node.
///
/// For example, you cannot nest a [RichText] widget as a descendant of
/// SwitchListTile. [RichText] has an embedded gesture recognizer that
/// requires its own [Semantics] node, which directly conflicts with
/// SwitchListTile's desire to merge all its descendants' semantic nodes
/// into one. Therefore, it may be necessary to create a custom radio tile
/// widget to accommodate similar use cases.
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Switch list tile semantics sample](https://flutter.github.io/assets-for-api-docs/assets/material/switch_list_tile_semantics.png)
///
/// Here is an example of a custom labeled radio widget, called
/// LinkedLabelRadio, that includes an interactive [RichText] widget that
/// handles tap gestures.
///
/// ```dart imports
/// import 'package:flutter/gestures.dart';
/// ```
/// ```dart preamble
/// class LinkedLabelSwitch extends StatelessWidget {
/// const LinkedLabelSwitch({
/// this.label,
/// this.padding,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool value;
/// final Function onChanged;
///
/// @override
/// Widget build(BuildContext context) {
/// return Padding(
/// padding: padding,
/// child: Row(
/// children: <Widget>[
/// Expanded(
/// child: RichText(
/// text: TextSpan(
/// text: label,
/// style: TextStyle(
/// color: Colors.blueAccent,
/// decoration: TextDecoration.underline,
/// ),
/// recognizer: TapGestureRecognizer()
/// ..onTap = () {
/// print('Label has been tapped.');
/// },
/// ),
/// ),
/// ),
/// Switch(
/// value: value,
/// onChanged: (bool newValue) {
/// onChanged(newValue);
/// },
/// ),
/// ],
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Center(
/// child: LinkedLabelSwitch(
/// label: 'Linked, tappable label text',
/// padding: const EdgeInsets.symmetric(horizontal: 20.0),
/// value: _isSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isSelected = newValue;
/// });
/// },
/// ),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// ## SwitchListTile isn't exactly what I want
///
/// If the way SwitchListTile pads and positions its elements isn't quite what
/// you're looking for, you can create custom labeled switch widgets by
/// combining [Switch] with other widgets, such as [Text], [Padding] and
/// [InkWell].
///
/// {@tool snippet --template=stateful_widget_scaffold}
///
/// ![Custom switch list tile sample](https://flutter.github.io/assets-for-api-docs/assets/material/switch_list_tile_custom.png)
///
/// Here is an example of a custom LabeledSwitch widget, but you can easily
/// make your own configurable widget.
///
/// ```dart preamble
/// class LabeledSwitch extends StatelessWidget {
/// const LabeledSwitch({
/// this.label,
/// this.padding,
/// this.groupValue,
/// this.value,
/// this.onChanged,
/// });
///
/// final String label;
/// final EdgeInsets padding;
/// final bool groupValue;
/// final bool value;
/// final Function onChanged;
///
/// @override
/// Widget build(BuildContext context) {
/// return InkWell(
/// onTap: () {
/// onChanged(!value);
/// },
/// child: Padding(
/// padding: padding,
/// child: Row(
/// children: <Widget>[
/// Expanded(child: Text(label)),
/// Switch(
/// value: value,
/// onChanged: (bool newValue) {
/// onChanged(newValue);
/// },
/// ),
/// ],
/// ),
/// ),
/// );
/// }
/// }
/// ```
/// ```dart
/// bool _isSelected = false;
///
/// @override
/// Widget build(BuildContext context) {
/// return Scaffold(
/// body: Center(
/// child: LabeledSwitch(
/// label: 'This is the label text',
/// padding: const EdgeInsets.symmetric(horizontal: 20.0),
/// value: _isSelected,
/// onChanged: (bool newValue) {
/// setState(() {
/// _isSelected = newValue;
/// });
/// },
/// ),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also: /// See also:
/// ///
/// * [ListTileTheme], which can be used to affect the style of list tiles, /// * [ListTileTheme], which can be used to affect the style of list tiles,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment