Unverified Commit a24bfed0 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Add autofocus parameter to widgets which use Focus widget internally (#37809)

Add an autofocus parameter to widgets which use Focus widget internally, and update related docs.

This will allow developers to request that a particular widget be automatically focused when shown.
parent 5acf63d3
...@@ -160,7 +160,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe ...@@ -160,7 +160,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
/// Design UI conventions. /// Design UI conventions.
/// * [EditableText], which is the raw text editing control at the heart of a /// * [EditableText], which is the raw text editing control at the heart of a
/// [TextField]. /// [TextField].
/// * Learn how to use a [TextEditingController] in one of our [cookbook recipe]s.(https://flutter.dev/docs/cookbook/forms/text-field-changes#2-use-a-texteditingcontroller) /// * Learn how to use a [TextEditingController] in one of our [cookbook recipes](https://flutter.dev/docs/cookbook/forms/text-field-changes#2-use-a-texteditingcontroller).
class CupertinoTextField extends StatefulWidget { class CupertinoTextField extends StatefulWidget {
/// Creates an iOS-style text field. /// Creates an iOS-style text field.
/// ///
...@@ -179,6 +179,13 @@ class CupertinoTextField extends StatefulWidget { ...@@ -179,6 +179,13 @@ class CupertinoTextField extends StatefulWidget {
/// The text cursor is not shown if [showCursor] is false or if [showCursor] /// The text cursor is not shown if [showCursor] is false or if [showCursor]
/// is null (the default) and [readOnly] is true. /// is null (the default) and [readOnly] is true.
/// ///
/// If specified, the [maxLength] property must be greater than zero.
///
/// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior],
/// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly],
/// [scrollPadding], [suffixMode], and [textAlign] properties must not be
/// null.
///
/// See also: /// See also:
/// ///
/// * [minLines] /// * [minLines]
...@@ -276,9 +283,7 @@ class CupertinoTextField extends StatefulWidget { ...@@ -276,9 +283,7 @@ class CupertinoTextField extends StatefulWidget {
/// If null, this widget will create its own [TextEditingController]. /// If null, this widget will create its own [TextEditingController].
final TextEditingController controller; final TextEditingController controller;
/// Controls whether this widget has keyboard focus. /// {@macro flutter.widgets.Focus.focusNode}
///
/// If null, this widget will create its own [FocusNode].
final FocusNode focusNode; final FocusNode focusNode;
/// Controls the [BoxDecoration] of the box behind the text input. /// Controls the [BoxDecoration] of the box behind the text input.
......
...@@ -31,9 +31,9 @@ class RawMaterialButton extends StatefulWidget { ...@@ -31,9 +31,9 @@ class RawMaterialButton extends StatefulWidget {
/// Create a button based on [Semantics], [Material], and [InkWell] widgets. /// Create a button based on [Semantics], [Material], and [InkWell] widgets.
/// ///
/// The [shape], [elevation], [focusElevation], [hoverElevation], /// The [shape], [elevation], [focusElevation], [hoverElevation],
/// [highlightElevation], [disabledElevation], [padding], [constraints], and /// [highlightElevation], [disabledElevation], [padding], [constraints],
/// [clipBehavior] arguments must not be null. Additionally, [elevation], /// [autofocus], and [clipBehavior] arguments must not be null. Additionally,
/// [focusElevation], [hoverElevation], [highlightElevation], and /// [elevation], [focusElevation], [hoverElevation], [highlightElevation], and
/// [disabledElevation] must be non-negative. /// [disabledElevation] must be non-negative.
const RawMaterialButton({ const RawMaterialButton({
Key key, Key key,
...@@ -56,6 +56,7 @@ class RawMaterialButton extends StatefulWidget { ...@@ -56,6 +56,7 @@ class RawMaterialButton extends StatefulWidget {
this.animationDuration = kThemeChangeDuration, this.animationDuration = kThemeChangeDuration,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.focusNode, this.focusNode,
this.autofocus = false,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
this.child, this.child,
}) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded, }) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
...@@ -69,6 +70,7 @@ class RawMaterialButton extends StatefulWidget { ...@@ -69,6 +70,7 @@ class RawMaterialButton extends StatefulWidget {
assert(constraints != null), assert(constraints != null),
assert(animationDuration != null), assert(animationDuration != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(autofocus != null),
super(key: key); super(key: key);
/// Called when the button is tapped or otherwise activated. /// Called when the button is tapped or otherwise activated.
...@@ -232,14 +234,12 @@ class RawMaterialButton extends StatefulWidget { ...@@ -232,14 +234,12 @@ class RawMaterialButton extends StatefulWidget {
/// * [MaterialTapTargetSize], for a description of how this affects tap targets. /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
/// An optional focus node to use for requesting focus when pressed. /// {@macro flutter.widgets.Focus.focusNode}
///
/// If not supplied, the button will create and host its own [FocusNode].
///
/// If supplied, the given focusNode will be _hosted_ by this widget. See
/// [FocusNode] for more information on what that implies.
final FocusNode focusNode; final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// {@macro flutter.widgets.Clip} /// {@macro flutter.widgets.Clip}
final Clip clipBehavior; final Clip clipBehavior;
...@@ -331,6 +331,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> { ...@@ -331,6 +331,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
final Widget result = Focus( final Widget result = Focus(
focusNode: widget.focusNode, focusNode: widget.focusNode,
onFocusChange: _handleFocusedChanged, onFocusChange: _handleFocusedChanged,
autofocus: widget.autofocus,
child: ConstrainedBox( child: ConstrainedBox(
constraints: widget.constraints, constraints: widget.constraints,
child: Material( child: Material(
......
This diff is collapsed.
...@@ -97,6 +97,8 @@ import 'theme_data.dart'; ...@@ -97,6 +97,8 @@ import 'theme_data.dart';
/// * <https://material.io/design/components/buttons.html> /// * <https://material.io/design/components/buttons.html>
class FlatButton extends MaterialButton { class FlatButton extends MaterialButton {
/// Create a simple text button. /// Create a simple text button.
///
/// The [autofocus] and [clipBehavior] arguments must not be null.
const FlatButton({ const FlatButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
...@@ -115,9 +117,11 @@ class FlatButton extends MaterialButton { ...@@ -115,9 +117,11 @@ class FlatButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
@required Widget child, @required Widget child,
}) : super( }) : assert(autofocus != null),
super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
...@@ -135,6 +139,7 @@ class FlatButton extends MaterialButton { ...@@ -135,6 +139,7 @@ class FlatButton extends MaterialButton {
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
child: child, child: child,
); );
...@@ -164,6 +169,7 @@ class FlatButton extends MaterialButton { ...@@ -164,6 +169,7 @@ class FlatButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
@required Widget icon, @required Widget icon,
@required Widget label, @required Widget label,
...@@ -192,6 +198,7 @@ class FlatButton extends MaterialButton { ...@@ -192,6 +198,7 @@ class FlatButton extends MaterialButton {
shape: buttonTheme.getShape(this), shape: buttonTheme.getShape(this),
clipBehavior: clipBehavior ?? Clip.none, clipBehavior: clipBehavior ?? Clip.none,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this), materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
animationDuration: buttonTheme.getAnimationDuration(this), animationDuration: buttonTheme.getAnimationDuration(this),
child: child, child: child,
...@@ -222,11 +229,13 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin { ...@@ -222,11 +229,13 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
@required Widget icon, @required Widget icon,
@required Widget label, @required Widget label,
}) : assert(icon != null), }) : assert(icon != null),
assert(label != null), assert(label != null),
assert(autofocus != null),
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
...@@ -245,6 +254,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin { ...@@ -245,6 +254,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
......
...@@ -145,6 +145,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -145,6 +145,7 @@ class FloatingActionButton extends StatelessWidget {
this.shape, this.shape,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.focusNode, this.focusNode,
this.autofocus = false,
this.materialTapTargetSize, this.materialTapTargetSize,
this.isExtended = false, this.isExtended = false,
}) : assert(elevation == null || elevation >= 0.0), }) : assert(elevation == null || elevation >= 0.0),
...@@ -154,15 +155,16 @@ class FloatingActionButton extends StatelessWidget { ...@@ -154,15 +155,16 @@ class FloatingActionButton extends StatelessWidget {
assert(disabledElevation == null || disabledElevation >= 0.0), assert(disabledElevation == null || disabledElevation >= 0.0),
assert(mini != null), assert(mini != null),
assert(isExtended != null), assert(isExtended != null),
assert(autofocus != null),
_sizeConstraints = mini ? _kMiniSizeConstraints : _kSizeConstraints, _sizeConstraints = mini ? _kMiniSizeConstraints : _kSizeConstraints,
super(key: key); super(key: key);
/// Creates a wider [StadiumBorder]-shaped floating action button with /// Creates a wider [StadiumBorder]-shaped floating action button with
/// an optional [icon] and a [label]. /// an optional [icon] and a [label].
/// ///
/// The [label] and [clipBehavior] arguments must non-null. Additionally, /// The [label], [autofocus], and [clipBehavior] arguments must non-null.
/// [elevation], [highlightElevation], and [disabledElevation] (if specified) /// Additionally, [elevation], [highlightElevation], and [disabledElevation]
/// must be non-negative. /// (if specified) must be non-negative.
FloatingActionButton.extended({ FloatingActionButton.extended({
Key key, Key key,
this.tooltip, this.tooltip,
...@@ -183,6 +185,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -183,6 +185,7 @@ class FloatingActionButton extends StatelessWidget {
this.materialTapTargetSize, this.materialTapTargetSize,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.focusNode, this.focusNode,
this.autofocus = false,
Widget icon, Widget icon,
@required Widget label, @required Widget label,
}) : assert(elevation == null || elevation >= 0.0), }) : assert(elevation == null || elevation >= 0.0),
...@@ -191,6 +194,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -191,6 +194,7 @@ class FloatingActionButton extends StatelessWidget {
assert(highlightElevation == null || highlightElevation >= 0.0), assert(highlightElevation == null || highlightElevation >= 0.0),
assert(disabledElevation == null || disabledElevation >= 0.0), assert(disabledElevation == null || disabledElevation >= 0.0),
assert(isExtended != null), assert(isExtended != null),
assert(autofocus != null),
_sizeConstraints = _kExtendedSizeConstraints, _sizeConstraints = _kExtendedSizeConstraints,
mini = false, mini = false,
child = _ChildOverflowBox( child = _ChildOverflowBox(
...@@ -372,14 +376,12 @@ class FloatingActionButton extends StatelessWidget { ...@@ -372,14 +376,12 @@ class FloatingActionButton extends StatelessWidget {
/// floating action buttons are scaled and faded in. /// floating action buttons are scaled and faded in.
final bool isExtended; final bool isExtended;
/// An optional focus node to use for requesting focus when pressed. /// {@macro flutter.widgets.Focus.focusNode}
///
/// If not supplied, the button will create and host its own [FocusNode].
///
/// If supplied, the given focusNode will be _hosted_ by this widget. See
/// [FocusNode] for more information on what that implies.
final FocusNode focusNode; final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// Configures the minimum size of the tap target. /// Configures the minimum size of the tap target.
/// ///
/// Defaults to [ThemeData.materialTapTargetSize]. /// Defaults to [ThemeData.materialTapTargetSize].
...@@ -463,6 +465,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -463,6 +465,7 @@ class FloatingActionButton extends StatelessWidget {
shape: shape, shape: shape,
clipBehavior: clipBehavior ?? Clip.none, clipBehavior: clipBehavior ?? Clip.none,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
child: child, child: child,
); );
......
...@@ -131,8 +131,8 @@ class IconButton extends StatelessWidget { ...@@ -131,8 +131,8 @@ class IconButton extends StatelessWidget {
/// ///
/// Requires one of its ancestors to be a [Material] widget. /// Requires one of its ancestors to be a [Material] widget.
/// ///
/// The [iconSize], [padding], and [alignment] arguments must not be null (though /// The [iconSize], [padding], [autofocus], and [alignment] arguments must not
/// they each have default values). /// be null (though they each have default values).
/// ///
/// The [icon] argument must be specified, and is typically either an [Icon] /// The [icon] argument must be specified, and is typically either an [Icon]
/// or an [ImageIcon]. /// or an [ImageIcon].
...@@ -150,10 +150,12 @@ class IconButton extends StatelessWidget { ...@@ -150,10 +150,12 @@ class IconButton extends StatelessWidget {
this.disabledColor, this.disabledColor,
@required this.onPressed, @required this.onPressed,
this.focusNode, this.focusNode,
this.autofocus = false,
this.tooltip, this.tooltip,
}) : assert(iconSize != null), }) : assert(iconSize != null),
assert(padding != null), assert(padding != null),
assert(alignment != null), assert(alignment != null),
assert(autofocus != null),
assert(icon != null), assert(icon != null),
super(key: key); super(key: key);
...@@ -256,14 +258,12 @@ class IconButton extends StatelessWidget { ...@@ -256,14 +258,12 @@ class IconButton extends StatelessWidget {
/// If this is set to null, the button will be disabled. /// If this is set to null, the button will be disabled.
final VoidCallback onPressed; final VoidCallback onPressed;
/// An optional focus node to use for requesting focus when pressed. /// {@macro flutter.widgets.Focus.focusNode}
///
/// If not supplied, the button will create and host its own [FocusNode].
///
/// If supplied, the given focusNode will be _hosted_ by this widget. See
/// [FocusNode] for more information on what that implies.
final FocusNode focusNode; final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// Text that describes the action that will occur when the button is pressed. /// Text that describes the action that will occur when the button is pressed.
/// ///
/// This text is displayed when the user long-presses on the button and is /// This text is displayed when the user long-presses on the button and is
...@@ -312,6 +312,7 @@ class IconButton extends StatelessWidget { ...@@ -312,6 +312,7 @@ class IconButton extends StatelessWidget {
enabled: onPressed != null, enabled: onPressed != null,
child: Focus( child: Focus(
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
child: InkResponse( child: InkResponse(
onTap: onPressed, onTap: onPressed,
child: result, child: result,
......
...@@ -43,6 +43,11 @@ class MaterialButton extends StatelessWidget { ...@@ -43,6 +43,11 @@ class MaterialButton extends StatelessWidget {
/// Rather than creating a material button directly, consider using /// Rather than creating a material button directly, consider using
/// [FlatButton] or [RaisedButton]. To create a custom Material button /// [FlatButton] or [RaisedButton]. To create a custom Material button
/// consider using [RawMaterialButton]. /// consider using [RawMaterialButton].
///
/// The [autofocus] and [clipBehavior] arguments must not be null.
/// Additionally, [elevation], [hoverElevation], [focusElevation],
/// [highlightElevation], and [disabledElevation] must be non-negative, if
/// specified.
const MaterialButton({ const MaterialButton({
Key key, Key key,
@required this.onPressed, @required this.onPressed,
...@@ -66,12 +71,19 @@ class MaterialButton extends StatelessWidget { ...@@ -66,12 +71,19 @@ class MaterialButton extends StatelessWidget {
this.shape, this.shape,
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.focusNode, this.focusNode,
this.autofocus = false,
this.materialTapTargetSize, this.materialTapTargetSize,
this.animationDuration, this.animationDuration,
this.minWidth, this.minWidth,
this.height, this.height,
this.child, this.child,
}) : super(key: key); }) : assert(autofocus != null),
assert(elevation == null || elevation >= 0.0),
assert(focusElevation == null || focusElevation >= 0.0),
assert(hoverElevation == null || hoverElevation >= 0.0),
assert(highlightElevation == null || highlightElevation >= 0.0),
assert(disabledElevation == null || disabledElevation >= 0.0),
super(key: key);
/// The callback that is called when the button is tapped or otherwise activated. /// The callback that is called when the button is tapped or otherwise activated.
/// ///
...@@ -296,14 +308,12 @@ class MaterialButton extends StatelessWidget { ...@@ -296,14 +308,12 @@ class MaterialButton extends StatelessWidget {
/// {@macro flutter.widgets.Clip} /// {@macro flutter.widgets.Clip}
final Clip clipBehavior; final Clip clipBehavior;
/// An optional focus node to use for requesting focus when pressed. /// {@macro flutter.widgets.Focus.focusNode}
///
/// If not supplied, the button will create and host its own [FocusNode].
///
/// If supplied, the given focusNode will be _hosted_ by this widget. See
/// [FocusNode] for more information on what that implies.
final FocusNode focusNode; final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// Defines the duration of animated changes for [shape] and [elevation]. /// Defines the duration of animated changes for [shape] and [elevation].
/// ///
/// The default value is [kThemeChangeDuration]. /// The default value is [kThemeChangeDuration].
......
...@@ -57,7 +57,7 @@ class OutlineButton extends MaterialButton { ...@@ -57,7 +57,7 @@ class OutlineButton extends MaterialButton {
/// Create an outline button. /// Create an outline button.
/// ///
/// The [highlightElevation] argument must be null or a positive value /// The [highlightElevation] argument must be null or a positive value
/// and the [clipBehavior] argument must not be null. /// and the [autofocus] and [clipBehavior] arguments must not be null.
const OutlineButton({ const OutlineButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
...@@ -77,8 +77,10 @@ class OutlineButton extends MaterialButton { ...@@ -77,8 +77,10 @@ class OutlineButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
Widget child, Widget child,
}) : assert(highlightElevation == null || highlightElevation >= 0.0), }) : assert(highlightElevation == null || highlightElevation >= 0.0),
assert(autofocus != null),
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
...@@ -95,6 +97,7 @@ class OutlineButton extends MaterialButton { ...@@ -95,6 +97,7 @@ class OutlineButton extends MaterialButton {
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
child: child, child: child,
); );
...@@ -105,7 +108,7 @@ class OutlineButton extends MaterialButton { ...@@ -105,7 +108,7 @@ class OutlineButton extends MaterialButton {
/// at the start, and 16 at the end, with an 8 pixel gap in between. /// at the start, and 16 at the end, with an 8 pixel gap in between.
/// ///
/// The [highlightElevation] argument must be null or a positive value. The /// The [highlightElevation] argument must be null or a positive value. The
/// [icon], [label], and [clipBehavior] arguments must not be null. /// [icon], [label], [autofocus], and [clipBehavior] arguments must not be null.
factory OutlineButton.icon({ factory OutlineButton.icon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
...@@ -125,6 +128,7 @@ class OutlineButton extends MaterialButton { ...@@ -125,6 +128,7 @@ class OutlineButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus,
@required Widget icon, @required Widget icon,
@required Widget label, @required Widget label,
}) = _OutlineButtonWithIcon; }) = _OutlineButtonWithIcon;
...@@ -218,9 +222,11 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi ...@@ -218,9 +222,11 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
@required Widget icon, @required Widget icon,
@required Widget label, @required Widget label,
}) : assert(highlightElevation == null || highlightElevation >= 0.0), }) : assert(highlightElevation == null || highlightElevation >= 0.0),
assert(autofocus != null),
assert(icon != null), assert(icon != null),
assert(label != null), assert(label != null),
super( super(
...@@ -242,6 +248,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi ...@@ -242,6 +248,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
...@@ -274,9 +281,11 @@ class _OutlineButton extends StatefulWidget { ...@@ -274,9 +281,11 @@ class _OutlineButton extends StatefulWidget {
this.shape, this.shape,
this.clipBehavior, this.clipBehavior,
this.focusNode, this.focusNode,
this.autofocus = false,
this.child, this.child,
}) : assert(highlightElevation != null && highlightElevation >= 0.0), }) : assert(highlightElevation != null && highlightElevation >= 0.0),
assert(highlightedBorderColor != null), assert(highlightedBorderColor != null),
assert(autofocus != null),
super(key: key); super(key: key);
final VoidCallback onPressed; final VoidCallback onPressed;
...@@ -297,6 +306,7 @@ class _OutlineButton extends StatefulWidget { ...@@ -297,6 +306,7 @@ class _OutlineButton extends StatefulWidget {
final ShapeBorder shape; final ShapeBorder shape;
final Clip clipBehavior; final Clip clipBehavior;
final FocusNode focusNode; final FocusNode focusNode;
final bool autofocus;
final Widget child; final Widget child;
bool get enabled => onPressed != null; bool get enabled => onPressed != null;
......
...@@ -101,9 +101,10 @@ import 'theme_data.dart'; ...@@ -101,9 +101,10 @@ import 'theme_data.dart';
class RaisedButton extends MaterialButton { class RaisedButton extends MaterialButton {
/// Create a filled button. /// Create a filled button.
/// ///
/// The [elevation], [highlightElevation], [disabledElevation], and /// The [autofocus] and [clipBehavior] arguments must not be null.
/// [clipBehavior] arguments must not be null. Additionally, [elevation], /// Additionally, [elevation], [hoverElevation], [focusElevation],
/// [highlightElevation], and [disabledElevation] must be non-negative. /// [highlightElevation], and [disabledElevation] must be non-negative, if
/// specified.
const RaisedButton({ const RaisedButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
...@@ -127,10 +128,12 @@ class RaisedButton extends MaterialButton { ...@@ -127,10 +128,12 @@ class RaisedButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration, Duration animationDuration,
Widget child, Widget child,
}) : assert(elevation == null || elevation >= 0.0), }) : assert(autofocus != null),
assert(elevation == null || elevation >= 0.0),
assert(focusElevation == null || focusElevation >= 0.0), assert(focusElevation == null || focusElevation >= 0.0),
assert(hoverElevation == null || hoverElevation >= 0.0), assert(hoverElevation == null || hoverElevation >= 0.0),
assert(highlightElevation == null || highlightElevation >= 0.0), assert(highlightElevation == null || highlightElevation >= 0.0),
...@@ -158,6 +161,7 @@ class RaisedButton extends MaterialButton { ...@@ -158,6 +161,7 @@ class RaisedButton extends MaterialButton {
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
animationDuration: animationDuration, animationDuration: animationDuration,
child: child, child: child,
...@@ -191,6 +195,7 @@ class RaisedButton extends MaterialButton { ...@@ -191,6 +195,7 @@ class RaisedButton extends MaterialButton {
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior, Clip clipBehavior,
FocusNode focusNode, FocusNode focusNode,
bool autofocus,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration, Duration animationDuration,
@required Widget icon, @required Widget icon,
...@@ -220,6 +225,7 @@ class RaisedButton extends MaterialButton { ...@@ -220,6 +225,7 @@ class RaisedButton extends MaterialButton {
constraints: buttonTheme.getConstraints(this), constraints: buttonTheme.getConstraints(this),
shape: buttonTheme.getShape(this), shape: buttonTheme.getShape(this),
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
animationDuration: buttonTheme.getAnimationDuration(this), animationDuration: buttonTheme.getAnimationDuration(this),
materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this), materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
child: child, child: child,
...@@ -262,6 +268,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi ...@@ -262,6 +268,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi
ShapeBorder shape, ShapeBorder shape,
Clip clipBehavior = Clip.none, Clip clipBehavior = Clip.none,
FocusNode focusNode, FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize, MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration, Duration animationDuration,
@required Widget icon, @required Widget icon,
...@@ -271,6 +278,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi ...@@ -271,6 +278,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi
assert(disabledElevation == null || disabledElevation >= 0.0), assert(disabledElevation == null || disabledElevation >= 0.0),
assert(icon != null), assert(icon != null),
assert(label != null), assert(label != null),
assert(autofocus != null),
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
...@@ -291,6 +299,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi ...@@ -291,6 +299,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
animationDuration: animationDuration, animationDuration: animationDuration,
child: Row( child: Row(
......
...@@ -184,7 +184,10 @@ class SelectableText extends StatefulWidget { ...@@ -184,7 +184,10 @@ class SelectableText extends StatefulWidget {
/// If the [style] argument is null, the text will use the style from the /// If the [style] argument is null, the text will use the style from the
/// closest enclosing [DefaultTextStyle]. /// closest enclosing [DefaultTextStyle].
/// ///
/// The [data] parameter must not be null.
/// The [showCursor], [autofocus], [dragStartBehavior], and [data] parameters
/// must not be null. If specified, the [maxLines] argument must be greater
/// than zero.
const SelectableText( const SelectableText(
this.data, { this.data, {
Key key, Key key,
...@@ -225,6 +228,8 @@ class SelectableText extends StatefulWidget { ...@@ -225,6 +228,8 @@ class SelectableText extends StatefulWidget {
/// ///
/// The [textSpan] parameter must not be null and only contain [TextSpan] in /// The [textSpan] parameter must not be null and only contain [TextSpan] in
/// [textSpan.children]. Other type of [InlineSpan] is not allowed. /// [textSpan.children]. Other type of [InlineSpan] is not allowed.
///
/// The [autofocus] and [dragStartBehavior] arguments must not be null.
const SelectableText.rich( const SelectableText.rich(
this.textSpan, { this.textSpan, {
Key key, Key key,
......
...@@ -679,13 +679,7 @@ class _ToggleButton extends StatelessWidget { ...@@ -679,13 +679,7 @@ class _ToggleButton extends StatelessWidget {
/// The splash color for the button's [InkWell]. /// The splash color for the button's [InkWell].
final Color splashColor; final Color splashColor;
/// A leaf node in the focus tree for this button. /// {@macro flutter.widgets.Focus.focusNode}
///
/// Focus is used to determine which widget should be affected by keyboard
/// events. The focus tree keeps track of which widget is currently focused
/// on by the user.
///
/// See [FocusNode] for more information about how focus nodes are used.
final FocusNode focusNode; final FocusNode focusNode;
/// Called when the button is tapped or otherwise activated. /// Called when the button is tapped or otherwise activated.
......
...@@ -339,9 +339,12 @@ class EditableText extends StatefulWidget { ...@@ -339,9 +339,12 @@ class EditableText extends StatefulWidget {
/// The text cursor is not shown if [showCursor] is false or if [showCursor] /// The text cursor is not shown if [showCursor] is false or if [showCursor]
/// is null (the default) and [readOnly] is true. /// is null (the default) and [readOnly] is true.
/// ///
/// The [controller], [focusNode], [style], [cursorColor], [backgroundCursorColor], /// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus],
/// [textAlign], [dragStartBehavior], [rendererIgnoresPointer] and [readOnly] /// [showSelectionHandles], [enableInteractiveSelection], [forceLine],
/// arguments must not be null. /// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor],
/// [paintCursorAboveText], [textAlign], [dragStartBehavior], [scrollPadding],
/// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer], and
/// [readOnly] arguments must not be null.
EditableText({ EditableText({
Key key, Key key,
@required this.controller, @required this.controller,
......
...@@ -137,7 +137,7 @@ class Focus extends StatefulWidget { ...@@ -137,7 +137,7 @@ class Focus extends StatefulWidget {
/// ///
/// The [child] argument is required and must not be null. /// The [child] argument is required and must not be null.
/// ///
/// The [autofocus] argument must not be null. /// The [autofocus] and [skipTraversal] arguments must not be null.
const Focus({ const Focus({
Key key, Key key,
@required this.child, @required this.child,
...@@ -190,24 +190,33 @@ class Focus extends StatefulWidget { ...@@ -190,24 +190,33 @@ class Focus extends StatefulWidget {
/// focus. /// focus.
final ValueChanged<bool> onFocusChange; final ValueChanged<bool> onFocusChange;
/// {@template flutter.widgets.Focus.autofocus}
/// True if this widget will be selected as the initial focus when no other /// True if this widget will be selected as the initial focus when no other
/// node in its scope is currently focused. /// node in its scope is currently focused.
/// ///
/// Ideally, there is only one [Focus] with autofocus set in each /// Ideally, there is only one widget with autofocus set in each [FocusScope].
/// [FocusScope]. If there is more than one [Focus] with autofocus set, then /// If there is more than one widget with autofocus set, then the first one
/// the first one added to the tree will get focus. /// added to the tree will get focus.
///
/// Must not be null. Defaults to false.
/// {@endtemplate}
final bool autofocus; final bool autofocus;
/// An optional focus node to use as the focus node for this [Focus] widget. /// {@template flutter.widgets.Focus.focusNode}
/// An optional focus node to use as the focus node for this widget.
/// ///
/// If one is not supplied, then one will be allocated and owned by this /// If one is not supplied, then one will be automatically allocated, owned,
/// widget. /// and managed by this widget. The widget will be focusable even if a
/// [focusNode] is not supplied. If supplied, the given `focusNode` will be
/// _hosted_ by this widget, but not owned. See [FocusNode] for more
/// information on what being hosted and/or owned implies.
/// ///
/// Supplying a focus node is sometimes useful if an ancestor to this widget /// Supplying a focus node is sometimes useful if an ancestor to this widget
/// wants to control when this widget has the focus. The owner will be /// wants to control when this widget has the focus. The owner will be
/// responsible for calling [FocusNode.dispose] on the focus node when it is /// responsible for calling [FocusNode.dispose] on the focus node when it is
/// done with it, but this [Focus] widget will attach/detach and reparent the /// done with it, but this widget will attach/detach and reparent the node
/// node when needed. /// when needed.
/// {@endtemplate}
final FocusNode focusNode; final FocusNode focusNode;
/// Sets the [FocusNode.skipTraversal] flag on the focus node so that it won't /// Sets the [FocusNode.skipTraversal] flag on the focus node so that it won't
......
...@@ -31,18 +31,27 @@ class RawKeyboardListener extends StatefulWidget { ...@@ -31,18 +31,27 @@ class RawKeyboardListener extends StatefulWidget {
/// ///
/// For text entry, consider using a [EditableText], which integrates with /// For text entry, consider using a [EditableText], which integrates with
/// on-screen keyboards and input method editors (IMEs). /// on-screen keyboards and input method editors (IMEs).
///
/// The [focusNode] and [child] arguments are required and must not be null.
///
/// The [autofocus] argument must not be null.
const RawKeyboardListener({ const RawKeyboardListener({
Key key, Key key,
@required this.focusNode, @required this.focusNode,
@required this.onKey, this.autofocus = false,
this.onKey,
@required this.child, @required this.child,
}) : assert(focusNode != null), }) : assert(focusNode != null),
assert(autofocus != null),
assert(child != null), assert(child != null),
super(key: key); super(key: key);
/// Controls whether this widget has keyboard focus. /// {@macro flutter.widgets.Focus.focusNode}
final FocusNode focusNode; final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// Called whenever this widget receives a raw keyboard event. /// Called whenever this widget receives a raw keyboard event.
final ValueChanged<RawKeyEvent> onKey; final ValueChanged<RawKeyEvent> onKey;
...@@ -113,5 +122,11 @@ class _RawKeyboardListenerState extends State<RawKeyboardListener> { ...@@ -113,5 +122,11 @@ class _RawKeyboardListenerState extends State<RawKeyboardListener> {
} }
@override @override
Widget build(BuildContext context) => Focus(focusNode: widget.focusNode, child: widget.child); Widget build(BuildContext context) {
return Focus(
focusNode: widget.focusNode,
autofocus: widget.autofocus,
child: widget.child,
);
}
} }
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