This tutorial shows you how to use TextEditingController
on TextField
or TextFormField
in Flutter, including how to set the initial value, getting and setting text
and selection
values, as well as building TextSpan
from it.
If you have an editable text widget, you need to store the value somewhere. The simplest approach is by using a state variable to store the value of text. There is another powerful way by setting a TextEditingController
as the controller of a TextField
or TextFormField
.
Whenever the user modifies the text field, the controller notifies its listeners so that they know the text
and selection
properties. TextEditingController
also allows you to modify the text
and selection
. In this case, the controller will notify the text field so that it can update the view.
Creating TextEditingController
To create a new TextEditingController
, just call the constructor.
TextEditingController({ String text })
You can call it without the parameter, which means the initial text is empty. Usually it's stored as a state variable.
final _myController = TextEditingController()
Optionally you can also set the initial value by passing text
parameter.
final _myController = TextEditingController(text: 'Woolha')
Another way to create a TextEditingController
is by using fromValue
named constructor which accepts a TextEditingValue
as a required parameter.
TextEditingController.fromValue(TextEditingValue value)
Below is the example of using fromValue
.
final _myController = TextEditingController.fromValue(TextEditingValue(
text: 'Woolha',
));
When the widget is disposed, you also need to clean up the controller.
@override
void dispose() {
_myController.dispose();
super.dispose();
}
Binding to TextField
or TextFormField
The controller needs to be bound to a text field in order to listen for value changes on the field.
TextFormField(
key: Key('name'),
controller: _myController,
decoration: InputDecoration(
labelText: 'Name'
),
),
Getting text
and selection
Values
To get the value, just access the text
property of the controller.
_myController.text
If you need to get information about TextSelection
(which includes offset, affinity, etc.), use the selection
property.
_myController.selection
Setting text
and selection
Values
You can set the text value programmatically by assigning the text
property with a new value. By default the cursor will move to the beginning of the text. If you want to set the cursor elsewhere, you have to set the selection
property, as shown below.
String newText = 'Woolha.com';
_myController.text = newText;
_myController.selection = TextSelection.collapsed(offset: newText.length);
For clearing the text, Flutter provides clear()
method.
_myController.clear();
Building TextSpan
You can easily build a TextSpan
from a TextEditingController
.
TextSpan buildTextSpan({TextStyle style , bool withComposing})
style
is the TextStyle
to be applied on the generated TextSpan
. withComposing
is used to make the text appears in underline if value.composing.isValid
is true
.
Here's the example.
_myController.buildTextSpan(
style: TextStyle(color: Colors.red),,
withComposing: false
);
Although both parameters are optional, I recommend you to set withComposing
as sometimes it may have null
value.
Below is a simple app that utilizes TextEditingController
.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: TextEditingControllerExample(),
);
}
}
class TextEditingControllerExample extends StatefulWidget {
@override
_TextEditingControllerExampleState createState() {
return _TextEditingControllerExampleState();
}
}
class _TextEditingControllerExampleState extends State<TextEditingControllerExample> {
final _myController = TextEditingController(text: 'Woolha');
TextSpan _myTextSpan = TextSpan();
@override
void dispose() {
_myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
print("build");
return Scaffold(
appBar: AppBar(
title: Text('Woolha.com - Flutter Tutorial'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
key: Key('name'),
controller: _myController,
decoration: InputDecoration(
labelText: 'Name'
),
),
Wrap(
spacing: 20,
children: <Widget>[
RaisedButton(
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('${_myController.text}\n${_myController.selection.toString()}'),
);
},
);
},
child: Text('Show'),
),
RaisedButton(
onPressed: () {
String newText = 'Woolha.com';
_myController.text = newText;
_myController.selection = TextSelection.collapsed(offset: newText.length);
},
child: Text('Set Text'),
),
RaisedButton(
onPressed: () {
_myController.clear();
},
child: Text('Clear'),
),
RaisedButton(
onPressed: () {
setState(() {
_myTextSpan = _myController.buildTextSpan(
style: TextStyle(color: Colors.red),
withComposing: false
);
});
},
child: Text('Build TextSpan'),
),
],
)
],
),
),
RichText(
text: _myTextSpan,
)
],
)
),
);
}
}