flutter/examples/api/lib/widgets/focus_traversal/focus_traversal_group.0.dart
Greg Spencer 33403bd28e
Extract Sample code into examples/api (#87280)
This extracts the sample code out from the API doc comments, and places them in separate files on disk, allowing running of the examples locally, testing them, and building of slightly larger examples.
2021-08-25 09:45:12 -07:00

222 lines
7.4 KiB
Dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Template: dev/snippets/config/templates/stateless_widget_material.tmpl
//
// Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring
// of samples, and may be ignored if you are just exploring the sample.
// Flutter code sample for FocusTraversalGroup
//
//***************************************************************************
//* ▼▼▼▼▼▼▼▼ description ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
// 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.
//* ▲▲▲▲▲▲▲▲ description ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//***************************************************************************
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
//*****************************************************************************
//* ▼▼▼▼▼▼▼▼ code-preamble ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
/// A button wrapper that adds either a numerical or lexical order, depending on
/// the type of T.
class OrderedButton<T> extends StatefulWidget {
const OrderedButton({
Key? key,
required this.name,
this.canRequestFocus = true,
this.autofocus = false,
required this.order,
}) : super(key: key);
final String name;
final bool canRequestFocus;
final bool autofocus;
final T order;
@override
State<OrderedButton<T>> createState() => _OrderedButtonState<T>();
}
class _OrderedButtonState<T> extends State<OrderedButton<T>> {
late 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<T> 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());
}
Color? overlayColor(Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return Colors.red;
}
if (states.contains(MaterialState.hovered)) {
return Colors.blue;
}
return null; // defer to the default overlayColor
}
Color? foregroundColor(Set<MaterialState> states) {
if (states.contains(MaterialState.focused) ||
states.contains(MaterialState.hovered)) {
return Colors.white;
}
return null; // defer to the default foregroundColor
}
return FocusTraversalOrder(
order: order,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
focusNode: focusNode,
autofocus: widget.autofocus,
style: ButtonStyle(
overlayColor:
MaterialStateProperty.resolveWith<Color?>(overlayColor),
foregroundColor:
MaterialStateProperty.resolveWith<Color?>(foregroundColor),
),
onPressed: () => _handleOnPressed(),
child: Text(widget.name),
),
),
);
}
}
//* ▲▲▲▲▲▲▲▲ code-preamble ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//*****************************************************************************
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
@override
//********************************************************************
//* ▼▼▼▼▼▼▼▼ code ▼▼▼▼▼▼▼▼ (do not modify or remove section marker)
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".
final 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,
);
}),
),
),
],
),
),
);
}
//* ▲▲▲▲▲▲▲▲ code ▲▲▲▲▲▲▲▲ (do not modify or remove section marker)
//********************************************************************
}