0

I am making a TodoList and I am storing the value of a TextField in a variable using the onChanged parameter.

When I tap outside to dismiss the Software Keyboard on the iOS simulator it stores the value correctly.

If I use the enter /return button on the software Keyboard It stores null.

Why is this happening?

What can I do to avoid this behavior?

I am using the provider package as a state management solution.

class AddThingScreen extends StatelessWidget {
  String title;


  @override
  Widget build(BuildContext context) {

    return Container(
      color: Color(0xff757575),
      child: Container(
        padding: EdgeInsets.all(20),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topRight: Radius.circular(20),
            topLeft: Radius.circular(20),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
              'Add thing',
              style: TextStyle(
                color: Colors.lightBlueAccent,
                fontSize: 36.0,
              ),
            ),
            TextField(
              controller: textEditingController,
              autofocus: true,
              autocorrect: true,
              textAlign: TextAlign.center,
              decoration: InputDecoration(
                focusColor: Colors.lightBlueAccent,
              ),
              onChanged: (newThingTitle) {
                title = newThingTitle;
              },
            ),
            FlatButton.icon(
              color: Colors.lightBlueAccent,
              icon: Icon(
                Icons.add,
                color: Colors.white,
              ),
              label: Text(
                'Add it',
                style: TextStyle(
                  color: Colors.white,
                ),
                textAlign: TextAlign.center,
              ),
              onPressed: () {
                Provider.of<ThingData>(context).addThing(title);
                Navigator.pop(context);
              },
            )
          ],
        ),
      ),
    );
  }
}

As you can see I call a method I am storing in my ThingData class which adds a new thing to the list and then notifyListeners.

class ThingData extends ChangeNotifier {
  List<Thing> _things = [
    Thing(name: 'Buy Cheese', isDone: false),
    Thing(name: 'Buy Flatbread', isDone: true),
    Thing(name: 'Buy Hot Sauce', isDone: false),
  ];

  int get thingCount {
    return _things.length;
  }

  UnmodifiableListView<Thing> get thingsList {
    return UnmodifiableListView<Thing>(_things);
  }

  void addThing(String newThingTitle) {
    final thing = Thing(name: newThingTitle);
    _things.add(thing);
    notifyListeners();
  }
}

Patrick Kelly
  • 971
  • 7
  • 15

2 Answers2

2

Because you have defined title inside the body of the build method of a StatelessWidget.

If you actually want to store the state of the title, you need to use a StatelessWidget:

class AddThingScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _AddThingScreenState();
  }
}

class _AddThingScreen State extends State<AddThingScreen> {
  String title;

  @override
  initState() {
    super.initState();
    title = '';
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0xff757575),
      child: Container(
        padding: EdgeInsets.all(20),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topRight: Radius.circular(20),
            topLeft: Radius.circular(20),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
              'Add thing',
              style: TextStyle(
                color: Colors.lightBlueAccent,
                fontSize: 36.0,
              ),
            ),
            TextField(
              autofocus: true,
              autocorrect: true,
              textAlign: TextAlign.center,
              decoration: InputDecoration(
                focusColor: Colors.lightBlueAccent,
              ),
              onChanged: (newThingTitle) {
                setState(() => {
                  title = newThingTitle;
                });
              },
            ),
            FlatButton.icon(
              color: Colors.lightBlueAccent,
              icon: Icon(
                Icons.add,
                color: Colors.white,
              ),
              label: Text(
                'Add it',
                style: TextStyle(
                  color: Colors.white,
                ),
                textAlign: TextAlign.center,
              ),
              onPressed: () {
                Provider.of<ThingData>(context).addThing(title);
                Navigator.pop(context);
              },
            )
          ],
        ),
      ),
    );
  }
}
DAG
  • 6,710
  • 4
  • 39
  • 63
  • Good eye and this would be true if I were managing state locally but I am managing state using the Provider package. I will modify my question to be more accurate. Thank you for your effort. – Patrick Kelly Aug 14 '19 at 15:57
  • Sure, the final „thing“ is managed using a centralised state management, but the intermediate text is not, thus you need it to store somewhere, until you hand it off to `ThingData` – DAG Aug 14 '19 at 16:18
  • I have moved it out of the build method and the same behavior occurs. So I had 2 issues. You guys helped solve 1 I think the second issue is with the textInputAction on an iOS. I just testing now I will update with the solution. – Patrick Kelly Aug 14 '19 at 16:43
0

You need to add a keyboard action to your TextField:

TextFormField( 
  ...
  textInputAction: TextInputAction.done,
  ...
)

And then handle the behaviour with onFieldSubmited callback, like this:

TextFormField( 
  ...
  textInputAction: TextInputAction.done,
  onFieldSubmitted: (newThingTitle) {
    title = newThingTitle;
  },
  ...
)
nosmirck
  • 666
  • 9
  • 31