Search code examples
flutterkeyboardflutter-layoutfocus

How to detect focus in children from a parent widget


In flutter,

  1. How can a parent widget know if a child among many children widgets has received focus? For example, Can we know if a child in a Row widget's children has received focus?

  2. Can I detect this focus before the child widget receives it?


Solution

  • It actually depends on your take and which architecture you wanna follow. This snippet that I'm posting uses NotificationListener, a custom notification and a custom child widget. This might work for an application like a print or a callback, but you might need to change the architecture and use a state management tool to achieve greater things.

    Parent Widget class:

    class MyParentWidget extends StatelessWidget {
      const MyParentWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return NotificationListener<FocusNotification>(
          onNotification: (notification) {
            print("New widget focused: ${notification.childKey.toString()}");
            return true;
          },
          child: Row(
            children: List.generate(
              5,
              (index) => MyChildWidget(
                Key('widget-$index'),
              ),
            ),
          ),
        );
      }
    }
    

    Child Widget class:

    class MyChildWidget extends StatefulWidget {
      const MyChildWidget(Key key) : super(key: key);
    
      @override
      _MyChildWidgetState createState() => _MyChildWidgetState();
    }
    
    class _MyChildWidgetState extends State<MyChildWidget> {
      final node = FocusNode();
    
      @override
      initState() {
        node.addListener(() {
          if (node.hasFocus) {
            final notification = FocusNotification(widget.key!);
            notification.dispatch(context);
          }
        });
        super.initState();
      }
    
      @override
      dispose() {
        node.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return TextField(
          focusNode: node,
        );
      }
    }
    

    Custom Notification class:

    class FocusNotification extends Notification {
      const FocusNotification(this.childKey);
      final Key childKey;
    }