Interactive apps need input, and controllers must be managed correctly to avoid leaks and lost text.
Buttons: FilledButton, ElevatedButton, OutlinedButton, TextButton and IconButton take an onPressed callback. Pass null to show the button as disabled.
Gestures on arbitrary widgets: wrap them in GestureDetector (onTap, onLongPress, onPanUpdate...) or InkWell for a Material ripple.
Text input uses TextField (or TextFormField inside a form):
onChanged: (text) => ...fires on every keystroke.- A `TextEditingController` reads and sets the text programmatically:
controller.text,controller.clear(). Create it ininitState(or as a field) of aStateand dispose it indispose. decoration: InputDecoration(labelText: ..., hintText: ..., errorText: ...)styles it.keyboardType,textInputAction,obscureTextfor passwords,autofocus, andonSubmitted.- A
FocusNodecontrols focus;FocusScope.of(context).unfocus()hides the keyboard.
Selection controls are controlled widgets: Switch(value: on, onChanged: (v) => setState(() => on = v)), and likewise Checkbox, Radio, Slider, DropdownMenu. The widget shows whatever value you pass; it only reports changes, so you must store the new value and rebuild.
When the keyboard opens, Scaffold resizes its body by default; put forms in a scroll view so fields aren't hidden.
Example
import 'package:flutter/material.dart';
class NewTodo extends StatefulWidget {
const NewTodo({super.key});
@override
State<NewTodo> createState() => _NewTodoState();
}
class _NewTodoState extends State<NewTodo> {
final _controller = TextEditingController();
bool _urgent = false;
@override
void dispose() { _controller.dispose(); super.dispose(); }
@override
Widget build(BuildContext context) => Column(children: [
TextField(controller: _controller, decoration: const InputDecoration(labelText: 'Task')),
SwitchListTile(title: const Text('Urgent'), value: _urgent,
onChanged: (v) => setState(() => _urgent = v)),
FilledButton(
onPressed: () { debugPrint('${_controller.text} urgent=$_urgent'); _controller.clear(); },
child: const Text('Add'),
),
]);
}Remember
onPressed: nulldisables a button- Controllers are created in State and disposed in
dispose - Switches, checkboxes and sliders are controlled: store the value and rebuild
Watch out for
- Creating a TextEditingController inside
build, which resets the text on every rebuild and leaks.