Класс TextEditingController предназначен для управления ввода текста в виджет TextField.
TextEditingController устанавливается с помощью параметра controller конструктора классов
TextField
и TextFormField
.
Данный класс имеет два конструктора:
TextEditingController({String text}) TextEditingController.fromValue(TextEditingValue value)
Первый конструктор в качестве параметра принимает начальное значение, которое затем будет отображаться в ассоциированном текстовом поле.
Второй конструктор также принимает начальное значение, но в виде объекта TextEditingValue
TextEditingController позволяет контроллировать введенный и выделенный текст в поле ввода, для чего у него определены три свойства:
selection: выделенный текст в виде объекта TextSelection
text: текущий введенный текст в виде объекта String
value: текущее значение в виде объекта TextEditingValue
При изменении ввода в текстовом поле связанный объект TextEditingController
уведомляет слушателей об изменении. Для добавления слушателей -
функций обработного вызова в классе определен метод addListener()
. Все добавленные слушатели могут считать введенный текст,
а также выделенный текст и таким образом узнать о произошедших изменениях.
Когда объект TextEditingController больше не нужен, у него надо вызвать метод dispose()
. Это позволит осовободить все ресурсы,
используемые объектом.
Вначале определим простейшее приложение с использованием TextEditingController, который задает начальное значение для текстового поля:
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( home: Scaffold( body: Person(), appBar: AppBar(title: Text("METANIT.COM"))) )); } class Person extends StatefulWidget { Person({ Key key}) : super(key: key); @override _PersonState createState() => _PersonState(); } class _PersonState extends State<Person>{ String _name = "Tom"; final _controller = TextEditingController(); @override void initState() { super.initState(); _controller.text = _name; } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column(children:[ Text("Имя пользователя: $_name", style: TextStyle(fontSize: 22)), TextField( style: TextStyle(fontSize: 22), controller: _controller) ], crossAxisAlignment: CrossAxisAlignment.start); } }
Для виджета Person в данном случае определяется состояние в виде класса _PersonState
. Класс _PersonState
хранит состояние в
виде переменной _name
- условное имя пользователя. Но кроме того _PersonState
также определяет константу
_controller
, которая представляет объект TextEditingController
, с помощью которого мы будем отслеживать измнения переменной _name
.
По умолчанию переменная _name
уже имеет начальное значение - "Tom". И чтобы передать это значение в контроллер, переопределяем
метод initState класса State. Этот метод призван инициализировать состояние объекта State. И в данном случае мы
передаем свойству text
объекта TextEditingController значение переменной _name
. Благодаря этому текстовое поле получит
начальное значение.
Для того, чтобы объект TextEditingController освободил все связанные с ним ресурсы, в классе состояния переопределяем метод
dispose(), в котором вызываем метод dispose()
контроллера.
Далее при создании виджета TextField в его конструкторе устанавливаем используемый контроллер:
controller: _controller
В итоге при запуске приложения текстовое поле получит начальное значение:
Теперь добавим обработку изменения текста:
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( home: Scaffold( body: Person(), appBar: AppBar(title: Text("METANIT.COM"))) )); } class Person extends StatefulWidget { Person({ Key key}) : super(key: key); @override _PersonState createState() => _PersonState(); } class _PersonState extends State<Person>{ String _name = "Tom"; final _controller = TextEditingController(); _changeName(){ setState(() =>_name = _controller.text); } @override void initState() { super.initState(); _controller.text = _name; _controller.addListener(_changeName); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column(children:[ Text("Имя пользователя: $_name", style: TextStyle(fontSize: 22)), TextField( style: TextStyle(fontSize: 22), controller: _controller) ], crossAxisAlignment: CrossAxisAlignment.start); } }
При вводе весь вводимый текст будет храниться в свойстве text
объекта TextEditingController. Для его получения и изменения
переменной _name здесь определен метод _changeName
:
_changeName(){ setState(() =>_name = _controller.text); }
Но когда вызывать данный метод? Для отслеживания изменений при инициализации состояния в методе initState()
вызываем у TextEditingController метод addListener()
и в него передаем ту функцию, которая будет выполняться при изменении текста в TextEditingController.
_controller.addListener(_changeName);
Метод addListener()
принимает функцию, которая не принимает никаких параметров и ничего не возвращает - то есть в данном случае соответствует
определению метода _changeName()
. Однако мы могли и явным образом вызвать метод _changeName:
_controller.addListener((){ _changeName(); });
В итоге при изменении текста в текстовом поле также будет изменяться и состояние виджета Person: