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
This commit is contained in:
parent
95eed87640
commit
a0ed52caa6
@ -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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
///
|
///
|
||||||
/// 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';
|
|||||||
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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;
|
|||||||
/// 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;
|
|||||||
/// ```
|
/// ```
|
||||||
/// {@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';
|
|||||||
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
///
|
///
|
||||||
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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 }
|
|||||||
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
///
|
///
|
||||||
/// 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 }
|
|||||||
/// ```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 }
|
|||||||
/// ```
|
/// ```
|
||||||
/// {@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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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}
|
||||||
|
///
|
||||||
|
/// 
|
||||||
|
///
|
||||||
|
/// 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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user