How to listen focus change in flutter?

In Android, we can call setOnFocusChangeListener(), do something in onFocusChanged() method, but flutter does not provider onFocus() interface like onTap() in GestureDetector or onKey() in RawKeyboardListener.

I have read flutter api about focus, https://docs.flutter.io/flutter/widgets/FocusManager-class.html but I can't find a way to realize my request, anyone who can give me a hand?


Solution 1:

In addtion you can use Focus widget.

Focus(
  child: TextFormField(...),
  onFocusChange: (hasFocus) {
    if(hasFocus) {
      // do stuff
    }
  },
)

Solution 2:

Using FocusNode

Here is a fully correct answer. addListener shall be in initState(), not build(), because that would result in adding a listener every time a widget is built and you most likely don't want that.

import 'package:flutter/material.dart';

class SomeWidget extends StatefulWidget {
  @override
  _SomeWidgetState createState() => _SomeWidgetState();
}

class _SomeWidgetState extends State<SomeWidget> {
  final _focusNode = FocusNode();
    
  @override
  void initState() {
    super.initState();
    _focusNode.addListener(() {
      print("Has focus: ${_focusNode.hasFocus}");
    });
  }
    
  @override
  Widget build(BuildContext context) {
    return TextField(focusNode: _focusNode);
  }
    
  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }
}

Using flutter_hooks package

If you're by any chance using the flutter_hooks package, there is a dedicated useFocusNode hook.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class SomeWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final focusNode = useFocusNode();
    useEffect(() {
      focusNode.addListener(() {
        print("Has focus: ${focusNode.hasFocus}");
      });
      return; // You need this return if you have missing_return lint
    }, [focusNode]);

    return TextField(focusNode: focusNode);
  }
}