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

Add a sample for FocusTraversalGroup (#51161)

parent 6d4121c0
...@@ -422,12 +422,12 @@ class Focus extends StatefulWidget { ...@@ -422,12 +422,12 @@ class Focus extends StatefulWidget {
if (node == null) { if (node == null) {
if (!nullOk) { if (!nullOk) {
throw FlutterError( throw FlutterError(
'Focus.of() was called with a context that does not contain a Focus widget.\n' 'Focus.of() was called with a context that does not contain a Focus widget.\n'
'No Focus widget ancestor could be found starting from the context that was passed to ' 'No Focus widget ancestor could be found starting from the context that was passed to '
'Focus.of(). This can happen because you are using a widget that looks for a Focus ' 'Focus.of(). This can happen because you are using a widget that looks for a Focus '
'ancestor, and do not have a Focus widget descendant in the nearest FocusScope.\n' 'ancestor, and do not have a Focus widget descendant in the nearest FocusScope.\n'
'The context used was:\n' 'The context used was:\n'
' $context' ' $context'
); );
} }
return null; return null;
...@@ -435,14 +435,14 @@ class Focus extends StatefulWidget { ...@@ -435,14 +435,14 @@ class Focus extends StatefulWidget {
if (!scopeOk && node is FocusScopeNode) { if (!scopeOk && node is FocusScopeNode) {
if (!nullOk) { if (!nullOk) {
throw FlutterError( throw FlutterError(
'Focus.of() was called with a context that does not contain a Focus between the given ' 'Focus.of() was called with a context that does not contain a Focus between the given '
'context and the nearest FocusScope widget.\n' 'context and the nearest FocusScope widget.\n'
'No Focus ancestor could be found starting from the context that was passed to ' 'No Focus ancestor could be found starting from the context that was passed to '
'Focus.of() to the point where it found the nearest FocusScope widget. This can happen ' 'Focus.of() to the point where it found the nearest FocusScope widget. This can happen '
'because you are using a widget that looks for a Focus ancestor, and do not have a ' 'because you are using a widget that looks for a Focus ancestor, and do not have a '
'Focus widget ancestor in the current FocusScope.\n' 'Focus widget ancestor in the current FocusScope.\n'
'The context used was:\n' 'The context used was:\n'
' $context' ' $context'
); );
} }
return null; return null;
......
...@@ -1420,6 +1420,156 @@ class FocusTraversalOrder extends InheritedWidget { ...@@ -1420,6 +1420,156 @@ class FocusTraversalOrder extends InheritedWidget {
/// ///
/// By default, traverses in reading order using [ReadingOrderTraversalPolicy]. /// By default, traverses in reading order using [ReadingOrderTraversalPolicy].
/// ///
/// {@tool dartpad --template=stateless_widget_material}
/// This sample shows three rows of buttons, each grouped by a
/// [FocusTraversalGroup], each with different traversal order policies. Use tab
/// traversal to see the order they are traversed in. The first row follows a
/// numerical order, the second follows a lexical order (ordered to traverse
/// right to left), and the third ignores the numerical order assigned to it and
/// traverses in widget order.
///
/// ```dart preamble
/// /// A button wrapper that adds either a numerical or lexical order, depending on
/// /// the type of T.
/// class OrderedButton<T> extends StatefulWidget {
/// const OrderedButton({
/// this.name,
/// this.canRequestFocus = true,
/// this.autofocus = false,
/// this.order,
/// });
///
/// final String name;
/// final bool canRequestFocus;
/// final bool autofocus;
/// final T order;
///
/// @override
/// _OrderedButtonState createState() => _OrderedButtonState();
/// }
///
/// class _OrderedButtonState<T> extends State<OrderedButton<T>> {
/// FocusNode focusNode;
///
/// @override
/// void initState() {
/// super.initState();
/// focusNode = FocusNode(
/// debugLabel: widget.name,
/// canRequestFocus: widget.canRequestFocus,
/// );
/// }
///
/// @override
/// void dispose() {
/// focusNode?.dispose();
/// super.dispose();
/// }
///
/// @override
/// void didUpdateWidget(OrderedButton oldWidget) {
/// super.didUpdateWidget(oldWidget);
/// focusNode.canRequestFocus = widget.canRequestFocus;
/// }
///
/// void _handleOnPressed() {
/// focusNode.requestFocus();
/// print('Button ${widget.name} pressed.');
/// debugDumpFocusTree();
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// FocusOrder order;
/// if (widget.order is num) {
/// order = NumericFocusOrder((widget.order as num).toDouble());
/// } else {
/// order = LexicalFocusOrder(widget.order.toString());
/// }
///
/// return FocusTraversalOrder(
/// order: order,
/// child: Padding(
/// padding: const EdgeInsets.all(8.0),
/// child: OutlineButton(
/// focusNode: focusNode,
/// autofocus: widget.autofocus,
/// focusColor: Colors.red,
/// hoverColor: Colors.blue,
/// onPressed: () => _handleOnPressed(),
/// child: Text(widget.name),
/// ),
/// ),
/// );
/// }
/// }
/// ```
///
/// ```dart
/// Widget build(BuildContext context) {
/// return Container(
/// color: Colors.white,
/// child: FocusTraversalGroup(
/// policy: OrderedTraversalPolicy(),
/// child: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// // A group that is ordered with a numerical order, from left to right.
/// FocusTraversalGroup(
/// policy: OrderedTraversalPolicy(),
/// child: Row(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: List<Widget>.generate(3, (int index) {
/// return OrderedButton<num>(
/// name: 'num: $index',
/// // TRY THIS: change this to "3 - index" and see how the order changes.
/// order: index,
/// );
/// }),
/// ),
/// ),
/// // A group that is ordered with a lexical order, from right to left.
/// FocusTraversalGroup(
/// policy: OrderedTraversalPolicy(),
/// child: Row(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: List<Widget>.generate(3, (int index) {
/// // Order as "C" "B", "A".
/// String order =
/// String.fromCharCode('A'.codeUnitAt(0) + (2 - index));
/// return OrderedButton<String>(
/// name: 'String: $order',
/// order: order,
/// );
/// }),
/// ),
/// ),
/// // A group that orders in widget order, regardless of what the order is set to.
/// FocusTraversalGroup(
/// // Note that because this is NOT an OrderedTraversalPolicy, the
/// // assigned order of these OrderedButtons is ignored, and they
/// // are traversed in widget order. TRY THIS: change this to
/// // "OrderedTraversalPolicy()" and see that it now follows the
/// // numeric order set on them instead of the widget order.
/// policy: WidgetOrderTraversalPolicy(),
/// child: Row(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: List<Widget>.generate(3, (int index) {
/// return OrderedButton<num>(
/// name: 'ignored num: ${3 - index}',
/// order: 3 - index,
/// );
/// }),
/// ),
/// ),
/// ],
/// ),
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also: /// See also:
/// ///
/// * [FocusNode], for a description of the focus system. /// * [FocusNode], for a description of the focus system.
......
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