@@ -108,6 +108,7 @@ class Radio<T> extends StatefulWidget {
108
108
@required this .value,
109
109
@required this .groupValue,
110
110
@required this .onChanged,
111
+ this .toggleable = false ,
111
112
this .activeColor,
112
113
this .focusColor,
113
114
this .hoverColor,
@@ -116,6 +117,7 @@ class Radio<T> extends StatefulWidget {
116
117
this .focusNode,
117
118
this .autofocus = false ,
118
119
}) : assert (autofocus != null ),
120
+ assert (toggleable != null ),
119
121
super (key: key);
120
122
121
123
/// The value represented by this radio button.
@@ -155,6 +157,69 @@ class Radio<T> extends StatefulWidget {
155
157
/// ```
156
158
final ValueChanged <T > onChanged;
157
159
160
+ /// Set to true if this radio button is allowed to be returned to an
161
+ /// indeterminate state by selecting it again when selected.
162
+ ///
163
+ /// To indicate returning to an indeterminate state, [onChanged] will be
164
+ /// called with null.
165
+ ///
166
+ /// If true, [onChanged] can be called with [value] when selected while
167
+ /// [groupValue] != [value] , or with null when selected again while
168
+ /// [groupValue] == [value] .
169
+ ///
170
+ /// If false, [onChanged] will be called with [value] when it is selected
171
+ /// while [groupValue] != [value] , and only by selecting another radio button
172
+ /// in the group (i.e. changing the value of [groupValue] ) can this radio
173
+ /// button be unselected.
174
+ ///
175
+ /// The default is false.
176
+ ///
177
+ /// {@tool dartpad --template=stateful_widget_scaffold}
178
+ /// This example shows how to enable deselecting a radio button by setting the
179
+ /// [toggleable] attribute.
180
+ ///
181
+ /// ```dart
182
+ /// int groupValue;
183
+ /// static const List<String> selections = <String>[
184
+ /// 'Hercules Mulligan',
185
+ /// 'Eliza Hamilton',
186
+ /// 'Philip Schuyler',
187
+ /// 'Maria Reynolds',
188
+ /// 'Samuel Seabury',
189
+ /// ];
190
+ ///
191
+ /// @override
192
+ /// Widget build(BuildContext context) {
193
+ /// return Scaffold(
194
+ /// body: ListView.builder(
195
+ /// itemBuilder: (context, index) {
196
+ /// return Row(
197
+ /// mainAxisSize: MainAxisSize.min,
198
+ /// crossAxisAlignment: CrossAxisAlignment.center,
199
+ /// children: <Widget>[
200
+ /// Radio<int>(
201
+ /// value: index,
202
+ /// groupValue: groupValue,
203
+ /// // TRY THIS: Try setting the toggleable value to false and
204
+ /// // see how that changes the behavior of the widget.
205
+ /// toggleable: true,
206
+ /// onChanged: (int value) {
207
+ /// setState(() {
208
+ /// groupValue = value;
209
+ /// });
210
+ /// }),
211
+ /// Text(selections[index]),
212
+ /// ],
213
+ /// );
214
+ /// },
215
+ /// itemCount: selections.length,
216
+ /// ),
217
+ /// );
218
+ /// }
219
+ /// ```
220
+ /// {@end-tool}
221
+ final bool toggleable;
222
+
158
223
/// The color to use when this radio button is selected.
159
224
///
160
225
/// Defaults to [ThemeData.toggleableActiveColor] .
@@ -207,7 +272,7 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
207
272
};
208
273
}
209
274
210
- void _actionHandler (FocusNode node, Intent intent){
275
+ void _actionHandler (FocusNode node, Intent intent) {
211
276
if (widget.onChanged != null ) {
212
277
widget.onChanged (widget.value);
213
278
}
@@ -241,8 +306,13 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
241
306
}
242
307
243
308
void _handleChanged (bool selected) {
244
- if (selected)
309
+ if (selected == null ) {
310
+ widget.onChanged (null );
311
+ return ;
312
+ }
313
+ if (selected) {
245
314
widget.onChanged (widget.value);
315
+ }
246
316
}
247
317
248
318
@override
@@ -276,6 +346,7 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
276
346
focusColor: widget.focusColor ?? themeData.focusColor,
277
347
hoverColor: widget.hoverColor ?? themeData.hoverColor,
278
348
onChanged: enabled ? _handleChanged : null ,
349
+ toggleable: widget.toggleable,
279
350
additionalConstraints: additionalConstraints,
280
351
vsync: this ,
281
352
hasFocus: _focused,
@@ -297,13 +368,15 @@ class _RadioRenderObjectWidget extends LeafRenderObjectWidget {
297
368
@required this .hoverColor,
298
369
@required this .additionalConstraints,
299
370
this .onChanged,
371
+ @required this .toggleable,
300
372
@required this .vsync,
301
373
@required this .hasFocus,
302
374
@required this .hovering,
303
375
}) : assert (selected != null ),
304
376
assert (activeColor != null ),
305
377
assert (inactiveColor != null ),
306
378
assert (vsync != null ),
379
+ assert (toggleable != null ),
307
380
super (key: key);
308
381
309
382
final bool selected;
@@ -314,6 +387,7 @@ class _RadioRenderObjectWidget extends LeafRenderObjectWidget {
314
387
final Color focusColor;
315
388
final Color hoverColor;
316
389
final ValueChanged <bool > onChanged;
390
+ final bool toggleable;
317
391
final TickerProvider vsync;
318
392
final BoxConstraints additionalConstraints;
319
393
@@ -325,6 +399,7 @@ class _RadioRenderObjectWidget extends LeafRenderObjectWidget {
325
399
focusColor: focusColor,
326
400
hoverColor: hoverColor,
327
401
onChanged: onChanged,
402
+ tristate: toggleable,
328
403
vsync: vsync,
329
404
additionalConstraints: additionalConstraints,
330
405
hasFocus: hasFocus,
@@ -340,6 +415,7 @@ class _RadioRenderObjectWidget extends LeafRenderObjectWidget {
340
415
..focusColor = focusColor
341
416
..hoverColor = hoverColor
342
417
..onChanged = onChanged
418
+ ..tristate = toggleable
343
419
..additionalConstraints = additionalConstraints
344
420
..vsync = vsync
345
421
..hasFocus = hasFocus
@@ -355,18 +431,19 @@ class _RenderRadio extends RenderToggleable {
355
431
Color focusColor,
356
432
Color hoverColor,
357
433
ValueChanged <bool > onChanged,
434
+ bool tristate,
358
435
BoxConstraints additionalConstraints,
359
436
@required TickerProvider vsync,
360
437
bool hasFocus,
361
438
bool hovering,
362
439
}) : super (
363
440
value: value,
364
- tristate: false ,
365
441
activeColor: activeColor,
366
442
inactiveColor: inactiveColor,
367
443
focusColor: focusColor,
368
444
hoverColor: hoverColor,
369
445
onChanged: onChanged,
446
+ tristate: tristate,
370
447
additionalConstraints: additionalConstraints,
371
448
vsync: vsync,
372
449
hasFocus: hasFocus,
0 commit comments