Using TextEditingController for Multiple TextFields in Flutter

Abdullah Dundar
Codimis
Published in
4 min readNov 28, 2022

Under this title, which is my first medium post, I will try to give you information about the use of TextEditingController in cases where we use multiple TextFields in Flutter.

When creating players in group games, you may have noticed that multiple TextFields are used on the same page. Let’s try to go through such a scenario.

We know that we can access the text of a TextField with the texteditingController. So how do we manage when there are multiple TextFields on a page?

If we look at the 3 containers in the gif I gave as an example below, you may have noticed the ‘ready’ change, apart from the control of each text field. At the end of this article, you will understand the logic of this feature.

Firstly,

 static bool isEmpty = false;
static bool isReady = false;

We create our isEmpty and isReady variables that will help us check if our TextFields are empty.


final List<TextEditingController> _textEditingControllers = [
TextEditingController()
];

Then we create our list to hold the TextEditingController for each TextField.

Future<void> additemtoList(int index, int maxnumber) async {
while (index < maxnumber) {
_textEditingControllers.add(TextEditingController());
if (Provider.of<Player>(context, listen: false).textValueisEmpty.length <
Provider.of<GameSettingsModel>(context, listen: false).playerCount) {
Provider.of<Player>(context, listen: false)
.textValueisEmpty
.add(CreatePlayerViewModel.isEmpty);
}
index++;
}
}

Next, we write our ‘additemToList’ function that adds TextFieldControllers for each textField by working with as many player creation Containers as we can fit in our ListView.Builder, which I will show shortly. In this function, we will also be able to control the output of the text ‘ready’ by adding the ‘ready’ parameter to the textValueisEmpty list created for it. In addition, we have the state management method we use in this function, in our provider codes. Thanks to this structure, we can easily access the variables in other classes of our project and share them with our processes. To better understand this structure, you can refer to this link (https://pub.dev/packages/provider).

ListView.builder(
itemCount: Provider.of<GameSettingsModel>(context).playerCount,
itemBuilder: (context, index) {
additemtoList(
index,
Provider.of<GameSettingsModel>(context).playerCount,
);
return Padding(
padding: EdgeInsets.only(bottom: screenHeight / 45),
child: playerNameCreateContainer(
context,
index + 1,
isCheckOkay,
));
},
),

The above is the ListView.builder that we use with the function we wrote. The more players that are created thanks to the ListView, the more we can type the name of the container containing the textField. and every time it is created, we can add the boolean parameters texteditingController and isReady thanks to our additemtoList function.

TextField playerNameCreateTextField(
BuildContext context,
List<TextEditingController>? textEditingControllers,
List<bool>? textValueisEmpty,
int? order,
) {
return TextField(
onChanged: (value) {
setState(() {
if (value.isEmpty) {
textValueisEmpty![order! - 1] = false;
} else {
textValueisEmpty![order! - 1] = true;
}
});
},
maxLines: 1,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.white,
),
controller: textEditingControllers![order!],
cursorColor: Colors.white,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10),
labelText: AppLocalizations.of(context)!.createPlayerName,
floatingLabelBehavior: FloatingLabelBehavior.never,
labelStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide: BorderSide(
color: Colors.white,
width: 1.1,
),
),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide: BorderSide(
color: Color.fromRGBO(223, 97, 50, 1),
width: 4,
)),
fillColor: Colors.red,
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Color.fromRGBO(223, 97, 50, 1),
width: 1.1,
),
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
),
);

Finally, we create our TextField widget above. In order to be able to access the lists we have added in this widget and be able to act on the items there, List<TextEditingController>?textEditingControllers and List<Bool>? We define the textValueisEmpty parameters. In addition, we add the context parameter from BuildContext in State Management and int? order parameters so that we can operate over the index in ListView where we will use our widget. By assigning textEditingControllers [order!] to the Controller property of the widget we created, we can perform operations on the TextEditingController of the TextField we want in the list containing the TextEditingController.

Finally, if no text is entered in our TextField in the onChanged() case, the textValueisEmpty prevents the ‘Ready’ change from being made by keeping the boolean parameter corresponding to that textField in our list false. If text is entered, it will make the textValueisEmpty change to ‘Ready’ by making the boolean parameter corresponding to that textField in our list true.

Thank you for reading my first Medium post. I hope I was able to explain the subject. If you like my article and want to be informed about my articles that I will share later, you can follow me. You can reach us via e-mail or on LinkedIn.

--

--

Abdullah Dundar
Codimis
Writer for

I am student of Computer science. I am currently developing SAP&ABAP and ı do things what ı enjoy.