Commit 1a3adae1 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Use `@required` for onPressed and onChanged (#4534)

We now use the `@required` annotation to encourage developers to
explicitly set onPressed and onChanged callbacks to null when that would
disable the widget.

Fixes #287
parent cc446967
......@@ -103,7 +103,8 @@ class PageableListAppState extends State<PageableListApp> {
child: new Row(
children: <Widget>[
new Flexible(child: new Text('Scrolling wraps around')),
new Checkbox(value: itemsWrap)
// TODO(abarth): Actually make this checkbox change this value.
new Checkbox(value: itemsWrap, onChanged: null)
]
)
)
......
......@@ -106,7 +106,8 @@ class _ButtonsDemoState extends State<ButtonsDemo> {
}
),
new RaisedButton(
child: new Text('DISABLED')
child: new Text('DISABLED'),
onPressed: null
)
]
)
......@@ -126,7 +127,8 @@ class _ButtonsDemoState extends State<ButtonsDemo> {
}
),
new FlatButton(
child: new Text('DISABLED')
child: new Text('DISABLED'),
onPressed: null
)
]
)
......@@ -173,7 +175,8 @@ class _ButtonsDemoState extends State<ButtonsDemo> {
color: iconButtonToggle ? Theme.of(context).primaryColor : null
),
new IconButton(
icon: Icons.thumb_up
icon: Icons.thumb_up,
onPressed: null
)
]
.map((Widget button) => new SizedBox(width: 64.0, height: 64.0, child: button))
......
......@@ -59,8 +59,9 @@ class _PersistentBottomSheetDemoState extends State<PersistentBottomSheetDemo> {
key: _scaffoldKey,
appBar: new AppBar(title: new Text('Persistent bottom sheet')),
floatingActionButton: new FloatingActionButton(
child: new Icon(icon: Icons.add),
backgroundColor: Colors.redAccent[200]
onPressed: null,
backgroundColor: Colors.redAccent[200],
child: new Icon(icon: Icons.add)
),
body: new Center(
child: new RaisedButton(
......
......@@ -101,8 +101,8 @@ class _SelectionControlsDemoState extends State<SelectionControlsDemo> {
mainAxisAlignment: MainAxisAlignment.collapse,
children: <Widget>[
// Disabled checkboxes
new Checkbox(value: true),
new Checkbox(value: false)
new Checkbox(value: true, onChanged: null),
new Checkbox(value: false, onChanged: null)
]
)
]
......@@ -142,15 +142,18 @@ class _SelectionControlsDemoState extends State<SelectionControlsDemo> {
children: <Widget>[
new Radio<int>(
value: 0,
groupValue: 0
groupValue: 0,
onChanged: null
),
new Radio<int>(
value: 1,
groupValue: 0
groupValue: 0,
onChanged: null
),
new Radio<int>(
value: 2,
groupValue: 0
groupValue: 0,
onChanged: null
)
]
)
......@@ -171,8 +174,8 @@ class _SelectionControlsDemoState extends State<SelectionControlsDemo> {
});
}),
// Disabled switches
new Switch(value: true),
new Switch(value: false)
new Switch(value: true, onChanged: null),
new Switch(value: false, onChanged: null)
]
)
);
......
......@@ -34,7 +34,7 @@ class _SliderDemoState extends State<SliderDemo> {
}
)
),
new Center(child: new Slider(value: 0.25)),
new Center(child: new Slider(value: 0.25, onChanged: null)),
new Center(
child: new Slider(
value: _discreteValue,
......
......@@ -26,7 +26,8 @@ new RaisedButton(
// Buttons are disabled when onPressed isn't
// specified or is null.
new RaisedButton(
child: new Text('BUTTON TITLE')
child: new Text('BUTTON TITLE'),
onPressed: null
);
// END
......@@ -44,7 +45,8 @@ new FlatButton(
// Buttons are disabled when onPressed isn't
// specified or is null.
new FlatButton(
child: new Text('BUTTON TITLE')
child: new Text('BUTTON TITLE'),
onPressed: null
);
// END
......@@ -97,7 +99,8 @@ new Scaffold(
title: new Text('Demo')
),
floatingActionButton: new FloatingActionButton(
child: new Icon(icon: Icons.add)
child: new Icon(icon: Icons.add),
onPressed: null
)
);
// END
......@@ -127,7 +130,7 @@ new Checkbox(
// Create a disabled checkbox.
// Checkboxes are disabled when onChanged isn't
// specified or null.
new Checkbox(value: false);
new Checkbox(value: false, onChanged: null);
// END
......@@ -166,7 +169,8 @@ new Row(
// Creates a disabled radio button.
new Radio<int>(
value: 0,
groupValue: 0
groupValue: 0,
onChanged: null
);
// END
......@@ -188,7 +192,7 @@ new Switch(
// Create a disabled switch.
// Switches are disabled when onChanged isn't
// specified or null.
new Switch(value: false);
new Switch(value: false, onChanged: null);
// END
}
}
......
......@@ -52,7 +52,8 @@ class AdaptedGridItem extends StatelessWidget {
child: new Text(name)
),
new IconButton(
icon: Icons.more_vert
icon: Icons.more_vert,
onPressed: null
)
]
)
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'constants.dart';
......@@ -128,7 +129,7 @@ class MaterialButton extends StatefulWidget {
this.minWidth,
this.height,
this.padding,
this.onPressed,
@required this.onPressed,
this.child
}) : super(key: key);
......
......@@ -6,6 +6,7 @@ import 'dart:math' as math;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'constants.dart';
import 'debug.dart';
......@@ -42,19 +43,14 @@ class Checkbox extends StatelessWidget {
/// * [onChanged] is called when the value of the checkbox should change.
Checkbox({
Key key,
this.value,
this.activeColor,
this.onChanged
@required this.value,
@required this.onChanged,
this.activeColor
}) : super(key: key);
/// Whether this checkbox is checked.
final bool value;
/// The color to use when this checkbox is checked.
///
/// Defaults to accent color of the current [Theme].
final Color activeColor;
/// Called when the value of the checkbox should change.
///
/// The checkbox passes the new value to the callback but does not actually
......@@ -64,6 +60,11 @@ class Checkbox extends StatelessWidget {
/// If null, the checkbox will be displayed as disabled.
final ValueChanged<bool> onChanged;
/// The color to use when this checkbox is checked.
///
/// Defaults to accent color of the current [Theme].
final Color activeColor;
/// The width of a checkbox widget.
static const double width = 18.0;
......
......@@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/date_symbols.dart';
import 'package:intl/intl.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'debug.dart';
......@@ -37,10 +38,10 @@ class DatePicker extends StatefulWidget {
/// [showDatePicker] to show a date picker in a dialog.
DatePicker({
Key key,
this.selectedDate,
this.onChanged,
this.firstDate,
this.lastDate
@required this.selectedDate,
@required this.onChanged,
@required this.firstDate,
@required this.lastDate
}) : super(key: key) {
assert(selectedDate != null);
assert(firstDate != null);
......@@ -134,9 +135,9 @@ class _DatePickerState extends State<DatePicker> {
class _DatePickerHeader extends StatelessWidget {
_DatePickerHeader({
Key key,
this.selectedDate,
this.mode,
this.onModeChanged
@required this.selectedDate,
@required this.mode,
@required this.onModeChanged
}) : super(key: key) {
assert(selectedDate != null);
assert(mode != null);
......@@ -241,10 +242,10 @@ class DayPicker extends StatelessWidget {
/// Rarely used directly. Instead, typically used as part of a [DatePicker].
DayPicker({
Key key,
this.selectedDate,
this.currentDate,
this.onChanged,
this.displayedMonth
@required this.selectedDate,
@required this.currentDate,
@required this.onChanged,
@required this.displayedMonth
}) : super(key: key) {
assert(selectedDate != null);
assert(currentDate != null);
......@@ -365,10 +366,10 @@ class MonthPicker extends StatefulWidget {
/// Rarely used directly. Instead, typically used as part of a [DatePicker].
MonthPicker({
Key key,
this.selectedDate,
this.onChanged,
this.firstDate,
this.lastDate
@required this.selectedDate,
@required this.onChanged,
@required this.firstDate,
@required this.lastDate
}) : super(key: key) {
assert(selectedDate != null);
assert(onChanged != null);
......@@ -515,10 +516,10 @@ class YearPicker extends StatefulWidget {
/// Rarely used directly. Instead, typically used as part of a [DatePicker].
YearPicker({
Key key,
this.selectedDate,
this.onChanged,
this.firstDate,
this.lastDate
@required this.selectedDate,
@required this.onChanged,
@required this.firstDate,
@required this.lastDate
}) : super(key: key) {
assert(selectedDate != null);
assert(onChanged != null);
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'debug.dart';
import 'icon.dart';
......@@ -376,9 +377,9 @@ class DropDownButton<T> extends StatefulWidget {
/// defaults, so do not need to be specified).
DropDownButton({
Key key,
this.items,
this.value,
this.onChanged,
@required this.items,
@required this.value,
@required this.onChanged,
this.elevation: 8,
this.style,
this.iconSize: 36.0
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'button.dart';
import 'theme.dart';
......@@ -40,7 +41,7 @@ class FlatButton extends StatelessWidget {
/// caps.
FlatButton({
Key key,
this.onPressed,
@required this.onPressed,
this.textColor,
this.disabledTextColor,
this.color,
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'icon_theme_data.dart';
......@@ -49,7 +50,7 @@ class FloatingActionButton extends StatefulWidget {
this.backgroundColor,
this.elevation: 6,
this.highlightElevation: 12,
this.onPressed,
@required this.onPressed,
this.mini: false
}) : super(key: key);
......
......@@ -50,7 +50,7 @@ class IconButton extends StatelessWidget {
@required this.icon,
this.color,
this.disabledColor,
this.onPressed,
@required this.onPressed,
this.tooltip
}) : super(key: key);
......
......@@ -4,6 +4,7 @@
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'constants.dart';
import 'debug.dart';
......@@ -47,10 +48,10 @@ class Radio<T> extends StatelessWidget {
/// * [onChanged] is when the user selects this radio button.
Radio({
Key key,
this.value,
this.groupValue,
this.activeColor,
this.onChanged
@required this.value,
@required this.groupValue,
@required this.onChanged,
this.activeColor
}) : super(key: key);
/// The value represented by this radio button.
......@@ -62,11 +63,6 @@ class Radio<T> extends StatelessWidget {
/// [groupValue].
final T groupValue;
/// The color to use when this radio button is selected.
///
/// Defaults to accent color of the current [Theme].
final Color activeColor;
/// Called when the user selects this radio button.
///
/// The radio button passes [value] as a parameter to this callback. The radio
......@@ -76,6 +72,11 @@ class Radio<T> extends StatelessWidget {
/// If null, the radio button will be displayed as disabled.
final ValueChanged<T> onChanged;
/// The color to use when this radio button is selected.
///
/// Defaults to accent color of the current [Theme].
final Color activeColor;
bool get _enabled => onChanged != null;
Color _getInactiveColor(ThemeData themeData) {
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'button.dart';
import 'colors.dart';
......@@ -38,7 +39,7 @@ class RaisedButton extends StatelessWidget {
/// caps.
RaisedButton({
Key key,
this.onPressed,
@required this.onPressed,
this.color,
this.disabledColor,
this.elevation: 2,
......
......@@ -7,6 +7,7 @@ import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'constants.dart';
......@@ -50,13 +51,13 @@ class Slider extends StatelessWidget {
/// * [onChanged] is called when the user selects a new value for the slider.
Slider({
Key key,
this.value,
@required this.value,
@required this.onChanged,
this.min: 0.0,
this.max: 1.0,
this.divisions,
this.label,
this.activeColor,
this.onChanged
this.activeColor
}) : super(key: key) {
assert(value != null);
assert(min != null);
......@@ -70,6 +71,15 @@ class Slider extends StatelessWidget {
/// The slider's thumb is drawn at a position that corresponds to this value.
final double value;
/// Called when the user selects a new value for the slider.
///
/// The slider passes the new value to the callback but does not actually
/// change state until the parent widget rebuilds the slider with the new
/// value.
///
/// If null, the slider will be displayed as disabled.
final ValueChanged<double> onChanged;
/// The minium value the user can select.
///
/// Defaults to 0.0.
......@@ -97,15 +107,6 @@ class Slider extends StatelessWidget {
/// Defaults to accent color of the current [Theme].
final Color activeColor;
/// Called when the user selects a new value for the slider.
///
/// The slider passes the new value to the callback but does not actually
/// change state until the parent widget rebuilds the slider with the new
/// value.
///
/// If null, the slider will be displayed as disabled.
final ValueChanged<double> onChanged;
void _handleChanged(double value) {
assert(onChanged != null);
onChanged(value * (max - min) + min);
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'button.dart';
import 'flat_button.dart';
......@@ -46,7 +47,11 @@ class SnackBarAction extends StatefulWidget {
/// Creates an action for a [SnackBar].
///
/// The [label] and [onPressed] arguments must be non-null.
SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
SnackBarAction({
Key key,
this.label,
@required this.onPressed
}) : super(key: key) {
assert(label != null);
assert(onPressed != null);
}
......
......@@ -5,6 +5,7 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'constants.dart';
......@@ -42,16 +43,25 @@ class Switch extends StatelessWidget {
/// * [onChanged] is called when the user toggles with switch on or off.
Switch({
Key key,
this.value,
@required this.value,
@required this.onChanged,
this.activeColor,
this.activeThumbDecoration,
this.inactiveThumbDecoration,
this.onChanged
this.inactiveThumbDecoration
}) : super(key: key);
/// Whether this switch is on or off.
final bool value;
/// Called when the user toggles with switch on or off.
///
/// The switch passes the new value to the callback but does not actually
/// change state until the parent widget rebuilds the switch with the new
/// value.
///
/// If null, the switch will be displayed as disabled.
final ValueChanged<bool> onChanged;
/// The color to use when this switch is on.
///
/// Defaults to accent color of the current [Theme].
......@@ -67,15 +77,6 @@ class Switch extends StatelessWidget {
/// Defaults to a circular piece of material.
final Decoration inactiveThumbDecoration;
/// Called when the user toggles with switch on or off.
///
/// The switch passes the new value to the callback but does not actually
/// change state until the parent widget rebuilds the switch with the new
/// value.
///
/// If null, the switch will be displayed as disabled.
final ValueChanged<bool> onChanged;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
......
......@@ -8,6 +8,7 @@ import 'dart:math' as math;
import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'debug.dart';
......@@ -455,9 +456,9 @@ class TabBarSelection<T> extends StatefulWidget {
TabBarSelection({
Key key,
this.value,
this.values,
@required this.values,
this.onChanged,
this.child
@required this.child
}) : super(key: key) {
assert(values != null && values.length > 0);
assert(new Set<T>.from(values).length == values.length);
......
......@@ -6,6 +6,7 @@ import 'dart:math' as math;
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'colors.dart';
import 'theme.dart';
......@@ -119,8 +120,8 @@ class TimePicker extends StatefulWidget {
/// creates a time picker dialog.
TimePicker({
Key key,
this.selectedTime,
this.onChanged
@required this.selectedTime,
@required this.onChanged
}) : super(key: key) {
assert(selectedTime != null);
}
......@@ -180,10 +181,10 @@ class _TimePickerState extends State<TimePicker> {
// TODO(ianh): Localize!
class _TimePickerHeader extends StatelessWidget {
_TimePickerHeader({
this.selectedTime,
this.mode,
this.onModeChanged,
this.onChanged
@required this.selectedTime,
@required this.mode,
@required this.onModeChanged,
@required this.onChanged
}) {
assert(selectedTime != null);
assert(mode != null);
......@@ -393,9 +394,9 @@ class _DialPainter extends CustomPainter {
class _Dial extends StatefulWidget {
_Dial({
this.selectedTime,
this.mode,
this.onChanged
@required this.selectedTime,
@required this.mode,
@required this.onChanged
}) {
assert(selectedTime != null);
}
......
......@@ -65,6 +65,7 @@ void main() {
child: new Center(
child: new Switch(
value: false,
onChanged: null,
activeThumbDecoration: activeDecoration,
inactiveThumbDecoration: inactiveDecoration
)
......
......@@ -31,6 +31,7 @@ Widget buildFrame({ List<String> tabs, String value, bool isScrollable: false, K
child: new TabBarSelection<String>(
value: value,
values: tabs,
onChanged: null,
child: new TabBar<String>(
key: tabBarKey,
labels: new Map<String, TabLabel>.fromIterable(tabs, value: (String tab) => new TabLabel(text: tab)),
......
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