FocusableActionDetector class

A widget that combines the functionality of Actions, Shortcuts, MouseRegion and a Focus widget to create a detector that defines actions and key bindings, and provides callbacks for handling focus and hover highlights.

This widget can be used to give a control the required detection modes for focus and hover handling. It is most often used when authoring a new control widget, and the new control should be enabled for keyboard traversal and activation.

This example shows how keyboard interaction can be added to a custom control that changes color when hovered and focused, and can toggle a light when activated, either by touch or by hitting the X key on the keyboard.

This example defines its own key binding for the X key, but in this case, there is also a default key binding for ActivateAction in the default key bindings created by WidgetsApp (the parent for MaterialApp, and CupertinoApp), so the ENTER key will also activate the control.

import 'package:flutter/services.dart';

// ...

class FadButton extends StatefulWidget {
  const FadButton({Key key, this.onPressed, this.child}) : super(key: key);

  final VoidCallback onPressed;
  final Widget child;

  @override
  _FadButtonState createState() => _FadButtonState();
}

class _FadButtonState extends State<FadButton> {
  bool _focused = false;
  bool _hovering = false;
  bool _on = false;
  Map<LocalKey, ActionFactory> _actionMap;
  Map<LogicalKeySet, Intent> _shortcutMap;

  @override
  void initState() {
    super.initState();
    _actionMap = <LocalKey, ActionFactory>{
      ActivateAction.key: () {
        return CallbackAction(
          ActivateAction.key,
          onInvoke: (FocusNode node, Intent intent) => _toggleState(),
        );
      },
    };
    _shortcutMap = <LogicalKeySet, Intent>{
      LogicalKeySet(LogicalKeyboardKey.keyX): Intent(ActivateAction.key),
    };
  }

  Color get color {
    Color baseColor = Colors.lightBlue;
    if (_focused) {
      baseColor = Color.alphaBlend(Colors.black.withOpacity(0.25), baseColor);
    }
    if (_hovering) {
      baseColor = Color.alphaBlend(Colors.black.withOpacity(0.1), baseColor);
    }
    return baseColor;
  }

  void _toggleState() {
    setState(() {
      _on = !_on;
    });
  }

  void _handleFocusHighlight(bool value) {
    setState(() {
      _focused = value;
    });
  }

  void _handleHoveHighlight(bool value) {
    setState(() {
      _hovering = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _toggleState,
      child: FocusableActionDetector(
        actions: _actionMap,
        shortcuts: _shortcutMap,
        onShowFocusHighlight: _handleFocusHighlight,
        onShowHoverHighlight: _handleHoveHighlight,
        child: Row(
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(10.0),
              color: color,
              child: widget.child,
            ),
            Container(
              width: 30,
              height: 30,
              margin: EdgeInsets.all(10.0),
              color: _on ? Colors.red : Colors.transparent,
            ),
          ],
        ),
      ),
    );
  }
}

// ...

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('FocusableActionDetector Example'),
    ),
    body: Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: FlatButton(onPressed: () {}, child: Text('Press Me')),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: FadButton(onPressed: () {}, child: Text('And Me')),
          ),
        ],
      ),
    ),
  );
}

This widget doesn't have any visual representation, it is just a detector that provides focus and hover capabilities.

It hosts its own FocusNode or uses focusNode, if given.

Inheritance

Constructors

FocusableActionDetector({Key key, bool enabled: true, FocusNode focusNode, bool autofocus: false, Map<LogicalKeySet, Intent> shortcuts, Map<LocalKey, ActionFactory> actions, ValueChanged<bool> onShowFocusHighlight, ValueChanged<bool> onShowHoverHighlight, ValueChanged<bool> onFocusChange, @required Widget child })
Create a const FocusableActionDetector. [...]
const

Properties

actions Map<LocalKey, ActionFactory>
A map of Intent keys to ActionFactory factory methods that defines which actions this widget knows about. [...]
final
autofocus bool
True if this widget will be selected as the initial focus when no other node in its scope is currently focused. [...]
final
child Widget
The child widget for this FocusableActionDetector widget. [...]
final
enabled bool
Is this widget enabled or not. [...]
final
focusNode FocusNode
An optional focus node to use as the focus node for this widget. [...]
final
onFocusChange ValueChanged<bool>
A function that will be called when the focus changes. [...]
final
onShowFocusHighlight ValueChanged<bool>
A function that will be called when the focus highlight should be shown or hidden.
final
onShowHoverHighlight ValueChanged<bool>
A function that will be called when the hover highlight should be shown or hidden.
final
shortcuts Map<LogicalKeySet, Intent>
The map of shortcuts that the ShortcutManager will be given to manage. [...]
final
hashCode int
The hash code for this object. [...]
read-only, inherited
key Key
Controls how one widget replaces another widget in the tree. [...]
final, inherited
runtimeType Type
A representation of the runtime type of the object.
read-only, inherited

Methods

createState() → _FocusableActionDetectorState
Creates the mutable state for this widget at a given location in the tree. [...]
override
createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree. [...]
inherited
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children. [...]
@protected, inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node. [...]
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a non-existent method or property is accessed. [...]
inherited
toDiagnosticsNode({String name, DiagnosticsTreeStyle style }) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep. [...]
inherited
toString({DiagnosticLevel minLevel: DiagnosticLevel.debug }) String
Returns a string representation of this object.
inherited
toStringDeep({String prefixLineOne: '', String prefixOtherLines, DiagnosticLevel minLevel: DiagnosticLevel.debug }) String
Returns a string representation of this node and its descendants. [...]
inherited
toStringShallow({String joiner: ', ', DiagnosticLevel minLevel: DiagnosticLevel.debug }) String
Returns a one-line detailed description of the object. [...]
inherited
toStringShort() String
A short, textual description of this widget.
inherited

Operators

operator ==(dynamic other) bool
The equality operator. [...]
inherited