How to listen focus change in flutter?
Asked Answered
M

4

113

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://api.flutter.dev/flutter/widgets/FocusManager-class.html but I can't find a way to realize my request, anyone who can give me a hand?

Mansfield answered 25/12, 2017 at 1:48 Comment(2)
I agree - its hard to understand the intent from the documentation. Example would be great as well.Daimyo
Haider Abbas posted an Answer saying "You may use MouseRegion() events like https://api.flutter.dev/flutter/widgets/MouseRegion-class.html onEnter, onExit"Rohr
F
53

I suppose you are looking for FocusNode class. Use addListener method to add a listener function that listens to focus change.

Example
declare and define FocusNode

 var focusNode = FocusNode();
  @override
  void initState() {
    focusNode.addListener(() {
      print(focusNode.hasFocus);
    });
    super.initState();
  }

Use focus node in textfield

TextField(
            focusNode: focusNode,
          ),

Output

when textfield is focus you will get true else false

Freak answered 25/12, 2017 at 16:37 Comment(3)
Can you provide an example pleaseTheism
An example pleasePastel
without example, answer is USELESSClouet
P
198

In addtion you can use Focus widget.

Focus(
  child: TextFormField(...),
  onFocusChange: (hasFocus) {
    if(hasFocus) {
      // do stuff
    }
  },
)
Procaine answered 21/4, 2020 at 15:53 Comment(7)
Certainly cleaner than having to set up and maintain a FocusNode instance. And for this post there is a proper example. Seems this could be the accepted answer now. Nice, ThanksJarid
This doesn't fire if you tap back.Hershey
@Hershey It did when I tested it (with both TextFormField and TextField).National
It's definitely cleaner but depends on the use case. If we have more than one input field maintaining a focus node for each would be better.Sufferable
Almost a must if you're working with blocs and re-usable widgets!Amargo
onFocusChange will fire when you lose focus, too. So the variable hasFocus is misleading and should be renamed or replace with _ if you don't use it.Eyre
@chemturion It will fire, but hasFocus will evaluate to true if the node has focus and false if it does not. The name is appropriate. Booleans are typically named with the naming convention has-, is-, did-, etc.Griqua
N
114

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(() {
      void onFocusChange() {
        print("Has focus: ${focusNode.hasFocus}");
      }
      focusNode.addListener(onFocusChange);
      return () => focusNode.removeListener(onFocusChange);
    }, [focusNode]);

    return TextField(focusNode: focusNode);
  }
}
Nat answered 27/2, 2019 at 14:5 Comment(7)
Thanks @Albert221, I was going through this problem of receiving multiple calls, now I managed to solve.Delanty
Note: a node focus listener is called twice: when it acquires focus and when it loses the focus. Inside the callback node.hasFocus would be true or false respectivelyRuskin
@Nat Do we also need to call the remove listener in the dispose method ?Charissa
@Charissa no, it's not needed. Notifying listeners in a ChangeNotifer (which a FocusNode is) is illegal after its disposalNat
So... why is the second final focusNode in the build method if it's not supposed to be there?... Or it IS supposed to be there, if it's a HookWidget?! 🙄Mosa
@KarolinaHagegård the useFocusNode is a hook, that returns the FocusNode, but also manages its lifecycle. It's like the first snippet with initState and dispose, but hidden inside a hook as you can see here: github.com/rrousselGit/flutter_hooks/blob/master/packages/…Nat
Here's a permalink to the hook insides mentioned above, as the previous link no longer works: github.com/rrousselGit/flutter_hooks/blob/…Nat
F
53

I suppose you are looking for FocusNode class. Use addListener method to add a listener function that listens to focus change.

Example
declare and define FocusNode

 var focusNode = FocusNode();
  @override
  void initState() {
    focusNode.addListener(() {
      print(focusNode.hasFocus);
    });
    super.initState();
  }

Use focus node in textfield

TextField(
            focusNode: focusNode,
          ),

Output

when textfield is focus you will get true else false

Freak answered 25/12, 2017 at 16:37 Comment(3)
Can you provide an example pleaseTheism
An example pleasePastel
without example, answer is USELESSClouet
D
-3
class FocusChange {
     static void fieldFocusChange(BuildContext context, FocusNode 
     currentFocusNode,
     FocusNode nextFocusNode) {
     currentFocusNode.unfocus();
     FocusScope.of(context).requestFocus(nextFocusNode);
    }
}
Damar answered 16/4, 2023 at 6:28 Comment(1)
Remember that Stack Overflow isn't just intended to solve the immediate problem, but also to help future readers find solutions to similar problems, which requires understanding the underlying code. This is especially important for members of our community who are beginners, and not familiar with the syntax. Given that, can you edit your answer to include an explanation of what you're doing and why you believe it is the best approach?Hedvige

© 2022 - 2024 — McMap. All rights reserved.