Skip to content

Instantly share code, notes, and snippets.

@IhorKlimov
Last active June 12, 2018 11:32
Show Gist options
  • Save IhorKlimov/b463b5044b16300615e91a2de86d1735 to your computer and use it in GitHub Desktop.
Save IhorKlimov/b463b5044b16300615e91a2de86d1735 to your computer and use it in GitHub Desktop.
Flutter TextFormField
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
/// A [FormField] that contains a [BetterTextField].
///
/// This is a convenience widget that wraps a [BetterTextField] widget in a
/// [FormField].
///
/// A [Form] ancestor is not required. The [Form] simply makes it easier to
/// save, reset, or validate multiple fields at once. To use without a [Form],
/// pass a [GlobalKey] to the constructor and use [GlobalKey.currentState] to
/// save or reset the form field.
///
/// When a [controller] is specified, its [TextEditingController.text]
/// defines the [initialValue]. If this [FormField] is part of a scrolling
/// container that lazily constructs its children, like a [ListView] or a
/// [CustomScrollView], then a [controller] should be specified.
/// The controller's lifetime should be managed by a stateful widget ancestor
/// of the scrolling container.
///
/// If a [controller] is not specified, [initialValue] can be used to give
/// the automatically generated controller an initial value.
///
/// For a documentation about the various parameters, see [BetterTextField].
///
/// See also:
///
/// * <https://material.google.com/components/text-fields.html>
/// * [BetterTextField], which is the underlying text field without the [Form]
/// integration.
/// * [InputDecorator], which shows the labels and other visual elements that
/// surround the actual text editing widget.
class BetterTextFormField extends FormField<String> {
/// Creates a [FormField] that contains a [BetterTextField].
///
/// When a [controller] is specified, [initialValue] must be null (the
/// default). If [controller] is null, then a [TextEditingController]
/// will be constructed automatically and its `text` will be initialized
/// to [initalValue] or the empty string.
///
/// For documentation about the various parameters, see the [BetterTextField] class
/// and [new BetterTextField], the constructor.
BetterTextFormField({
Key key,
this.controller,
String initialValue,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType = TextInputType.text,
TextStyle style,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool obscureText = false,
bool autocorrect = true,
bool autovalidate = false,
bool maxLengthEnforced = true,
int maxLines = 1,
int maxLength,
ValueChanged<String> onFieldSubmitted,
FormFieldSetter<String> onSaved,
FormFieldValidator<String> validator,
List<TextInputFormatter> inputFormatters,
bool enabled,
}) : assert(initialValue == null || controller == null),
assert(keyboardType != null),
assert(textAlign != null),
assert(autofocus != null),
assert(obscureText != null),
assert(autocorrect != null),
assert(autovalidate != null),
assert(maxLengthEnforced != null),
assert(maxLines == null || maxLines > 0),
assert(maxLength == null || maxLength > 0),
super(
key: key,
initialValue: controller != null ? controller.text : (initialValue ?? ''),
onSaved: onSaved,
validator: validator,
autovalidate: autovalidate,
builder: (FormFieldState<String> field) {
final _BetterTextFormFieldState state = field;
final InputDecoration effectiveDecoration = (decoration ?? const InputDecoration())
.applyDefaults(Theme.of(field.context).inputDecorationTheme);
return new BetterTextField(
controller: state._effectiveController,
focusNode: focusNode,
decoration: effectiveDecoration.copyWith(errorText: field.errorText),
keyboardType: keyboardType,
style: style,
textAlign: textAlign,
autofocus: autofocus,
obscureText: obscureText,
autocorrect: autocorrect,
maxLengthEnforced: maxLengthEnforced,
maxLines: maxLines,
maxLength: maxLength,
onChanged: field.didChange,
onSubmitted: onFieldSubmitted,
inputFormatters: inputFormatters,
enabled: enabled,
);
},
);
/// Controls the text being edited.
///
/// If null, this widget will create its own [TextEditingController] and
/// initialize its [TextEditingController.text] with [initialValue].
final TextEditingController controller;
@override
_BetterTextFormFieldState createState() => new _BetterTextFormFieldState();
}
class _BetterTextFormFieldState extends FormFieldState<String> {
TextEditingController _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller;
@override
BetterTextFormField get widget => super.widget;
@override
void initState() {
super.initState();
if (widget.controller == null) {
_controller = new TextEditingController(text: widget.initialValue);
} else {
widget.controller.addListener(_handleControllerChanged);
}
}
@override
void didUpdateWidget(BetterTextFormField oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.controller != oldWidget.controller) {
oldWidget.controller?.removeListener(_handleControllerChanged);
widget.controller?.addListener(_handleControllerChanged);
if (oldWidget.controller != null && widget.controller == null)
_controller = new TextEditingController.fromValue(oldWidget.controller.value);
if (widget.controller != null) {
setValue(widget.controller.text);
if (oldWidget.controller == null)
_controller = null;
}
}
}
@override
void dispose() {
widget.controller?.removeListener(_handleControllerChanged);
super.dispose();
}
@override
void reset() {
super.reset();
setState(() {
_effectiveController.text = widget.initialValue;
});
}
void _handleControllerChanged() {
// Suppress changes that originated from within this class.
//
// In the case where a controller has been passed in to this widget, we
// register this change listener. In these cases, we'll also receive change
// notifications for changes originating from within this class -- for
// example, the reset() method. In such cases, the FormField value will
// already have been set.
if (_effectiveController.text != value)
didChange(_effectiveController.text);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment