TextField Loses Focus with setState

4,398

I have had the same problem. I have found that I use key: UniqueKey() in my container. On every setState it generates uniqueKey and updates the children. Check your keys.

Share:
4,398
Josh Kahane
Author by

Josh Kahane

Updated on December 09, 2022

Comments

  • Josh Kahane
    Josh Kahane about 1 year

    I have a custom StatefulWidget that when typing into an empty field, it will automatically add a new empty field below so the user can keep adding data.

    However, as I use setState in onChanged to add the new field, the keyboard is dismissed and focus is lost on the currently focused field.

    How can Io prevent this happening?

     TextField(
              hintText: widget.newEntryHint,
              text: data[index].value,
              onChanged: (val) {
                setState(() {
                  data[index].value = val;
        
                  //if last item in list, add an extra field below
                  if (val.length > 0 && index == (data.length -1)) {
                    data.add(TextListItem(value: ""));
                  }
                });
              },
            )
    

    Custom TextField for reference:

    class MyTextField extends StatefulWidget {
      MyTextField({
        this.text,
        this.hintText = "",
        this.onChanged,
        this.onSubmitted,
        this.textAlign = TextAlign.left,
        this.focusNode,
        this.autofocus = false,
        this.obscureText = false,
        this.padding = const EdgeInsets.all(0.0),
        this.keyboardType = TextInputType.text,
        this.canEdit = true,
        this.isDarkMode = false,
        this.textCapitalization = TextCapitalization.sentences,
        this.key,
      });
    
      final String text;
      final String hintText;
      final ValueChanged<String> onChanged;
      final ValueChanged<String> onSubmitted;
      final TextAlign textAlign;
      final FocusNode focusNode;
      final bool autofocus;
      final bool obscureText;
      final EdgeInsets padding;
      final TextInputType keyboardType;
      final TextCapitalization textCapitalization;
      final Key key;
    
      final bool canEdit;
    
      final isDarkMode;
    
      @override
      _MyTextFieldState createState() => _MyTextFieldState();
    }
    
    class _MyTextFieldState extends State<MyTextField> {
      static const double textFieldPadding = 12.0;
      TextEditingController editingController;
    
      @override
      void initState() {
        super.initState();
        editingController = TextEditingController(text: widget.text);
      }
    
      @override
      Widget build(BuildContext context) {
        return IgnorePointer(
          ignoring: !widget.canEdit,
          child: Column(
            children: <Widget>[
              Padding(
                padding: EdgeInsets.only(
                    top: textFieldPadding + widget.padding.top, bottom: textFieldPadding + widget.padding.bottom, left: widget.padding.left, right: widget.padding.right),
                child: TextField(
                  key: widget.key,
                  maxLines: null,
                  textCapitalization: widget.textCapitalization,
                  keyboardType: widget.keyboardType,
                  keyboardAppearance: widget.isDarkMode ? Brightness.dark : Brightness.light,
                  controller: editingController,
                  onSubmitted: widget.onSubmitted,
                  onChanged: widget.onChanged,
                  style: TextStyle(
                      color: widget.isDarkMode ? Colors.white : MyColors.textBlue,
                      fontSize: 16.0,
                      fontWeight: FontWeight.w500),
                  autofocus: widget.autofocus,
                  focusNode: widget.focusNode,
                  textAlign: widget.textAlign,
                  obscureText: widget.obscureText,
                  decoration: InputDecoration(
                    hintText: widget.hintText,
                    hintStyle: TextStyle(
                        color: widget.isDarkMode ? MyColors.black[700] : MyColors.grey,
                        fontSize: 16.0,
                        fontWeight: FontWeight.w500),
                    border: InputBorder.none,
                  ),
                ),
              ),
              Divider(
                color: widget.isDarkMode ? MyColors.black : MyColors.grey[150],
                height: 1.0,
              ),
            ],
          ),
        );
      }
    }
    
    • Jordan Davies
      Jordan Davies almost 5 years
      Are you using a custom TextField class? because the standard Flutter TextField doesn't have a text property.
    • Josh Kahane
      Josh Kahane almost 5 years
      Yep, I am using a custom class, but just applies some styling and direct text setting, per text property.
    • Jordan Davies
      Jordan Davies almost 5 years
      Ok, would be useful to see the source of that class in the question, as I suspect the problem is occurring in your custom class.
    • Josh Kahane
      Josh Kahane almost 5 years
      Added it in for reference.
  • nilecrocodile
    nilecrocodile over 3 years
    I have the same problem. Could you explain how you solved it?
  • Jan
    Jan over 2 years
    Thank you very much, I've replaced UniqueKey() with ValueKey(0) and now there is no issue with input in TextFormField, though Dissmisable widget now doesn't work as before. What did you mean with check your keys? How to solve this issue?
  • Mireille
    Mireille over 2 years
    I had the same problem, I was defining a GlobalKey() for my Scaffold inside build function, I just moved it outside the function.
  • shraddha11
    shraddha11 over 2 years
    i have same problem as mentioned by @Jan in above comment with dismissable widget? Have you found solution @Jan?
  • Jan
    Jan over 2 years
    shraddha11 no sorry I didn't found solution, instead I've made workaround, removed setState((){}) from onChanged parameter in TextFormField and then don't have this issue
  • genericUser
    genericUser almost 2 years
    @Jan @shraddha11 You will have to create a ValueKey based on a final id. For instance key: ValueKey(task.id) (inside your Dismissible).
  • genericUser
    genericUser almost 2 years
    I'm using a TextFormField inside a Dismissible widget. Although it solves the keyboard issue, now I'm facing an issue with the text cursor position. I'm using a setState on each text change, and each time the pointer jumps to the beginning of the text. How do I solve this?