import 'package:flutter/widgets.dart'; class TextEditingControllerBuilder extends StatefulWidget { /// Exposes a [TextEditingController] to the child, which allows /// us to convert any [TextField] into a declarative version. /// /// Typically used for wiring up many state fields to form inputs /// and making sure everything stays in sync. /// /// If [text] is updated, the consuming [TextField] will also be updated. /// If the ancestor is rebuilt, the composing state will not be lost like it typically is. const TextEditingControllerBuilder( {Key key, @required this.text, @required this.builder}) : super(key: key); /// The text to declaratively update in the text controller final String text; /// The builder which exposes the [TextEditingController] to the child final Widget Function(BuildContext, TextEditingController) builder; @override _TextEditingControllerBuilderState createState() => _TextEditingControllerBuilderState(); } class _TextEditingControllerBuilderState extends State { TextEditingController controller; bool get isBeingEdited => controller.value.composing.isValid || controller.value.selection.isValid; @override void initState() { controller = TextEditingController(text: widget.text); super.initState(); } @override void dispose() { controller?.dispose(); super.dispose(); } @override void didUpdateWidget(covariant TextEditingControllerBuilder oldWidget) { final hasTextChanges = oldWidget.text != widget.text; if (hasTextChanges && isBeingEdited == false) { controller.text = widget.text; } super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { return widget.builder(context, controller); } }