How To Create Custom TextField Class? - flutter

I am trying to create a custom textfield class so that i can easily change how it looks by only editing in one place. Currently i am facing a problem on how to make a toggle password visibility.
This is what my custom textfield class:
class CustomTextFieldOutline extends StatelessWidget {
CustomTextFieldOutline(
{this.label,
this.controller,
this.isValid,
this.invalidMsg});
final String label;
final TextEditingController controller;
final bool isValid;
final String invalidMsg;
#override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
labelText: label,
errorText: isValid ? null : invalidMsg,
errorStyle: TextStyle(color: constant.colorWhite),
labelStyle: TextStyle(color: constant.colorWhite),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
)),
style: TextStyle(color: constant.colorWhite),
controller: controller,
);
}
}
This is how i call it:
final _resetPasswordView = Container(
child: AnimatedOpacity(
opacity: _resetPasswordVisibility ? 1.0 : 0.0,
duration: Duration(milliseconds: 300),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
CustomTextFieldOutline(
label: constant.email,
controller: _emailSignInController,
isValid: _isEmailValid,
invalidMsg: _emailValidMsg,
)
],
),
),
)
This how my password textfield looks like. I am not using custome textfield class because i dont know how can i implement toggle password visibility in class:
TextField(
decoration: InputDecoration(
labelText: constant.password,
suffixIcon: GestureDetector(
onTap: () {
_togglePasswordVisibility();
},
child: Icon(
_isHidePassword ? Icons.visibility_off : Icons.visibility,
color: constant.colorWhite,
),
),
errorText: _isPasswordValid ? null : _passwordValidMsg,
errorStyle: TextStyle(color: constant.colorWhite),
labelStyle: TextStyle(color: constant.colorWhite),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: constant.colorWhite),
)),
style: TextStyle(color: constant.colorWhite),
obscureText: _isHidePassword,
controller: _passwordSignUpController,
)
How can i incorporate the password textfield functionality in the custom class so that i can use it for password or email textfield?

Here is a sample from instaflutter
class CustomTextField extends StatefulWidget {
final String hint;
final TextEditingController controller;
final Color baseColor;
final Color borderColor;
final Color errorColor;
final TextInputType inputType;
final bool obscureText;
final Function validator;
final Function onChanged;
CustomTextField(
{this.hint,
this.controller,
this.onChanged,
this.baseColor,
this.borderColor,
this.errorColor,
this.inputType = TextInputType.text,
this.obscureText = false,
this.validator});
_CustomTextFieldState createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
Color currentColor;
#override
void initState() {
super.initState();
currentColor = widget.borderColor;
}
#override
Widget build(BuildContext context) {
return Card(
elevation: 0.0,
color: Colors.white,
shape: RoundedRectangleBorder(
side: BorderSide(color: currentColor, width: 2.0),
borderRadius: BorderRadius.circular(20.0),
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: TextField(
obscureText: widget.obscureText,
onChanged: (text) {
if (widget.onChanged != null) {
widget.onChanged(text);
}
setState(() {
if (!widget.validator(text) || text.length == 0) {
currentColor = widget.errorColor;
} else {
currentColor = widget.baseColor;
}
});
},
//keyboardType: widget.inputType,
controller: widget.controller,
decoration: InputDecoration(
hintStyle: TextStyle(
color: widget.baseColor,
fontFamily: "OpenSans",
fontWeight: FontWeight.w300,
),
border: InputBorder.none,
hintText: widget.hint,
),
),
),
);
}
}
and then you can create your widgets
_emailField = new CustomTextField(
baseColor: Colors.grey,
borderColor: Colors.grey[400],
errorColor: Colors.red,
controller: _email,
hint: "E-mail Adress",
inputType: TextInputType.emailAddress,
validator: Validator.validateEmail,
);
_passwordField = CustomTextField(
baseColor: Colors.grey,
borderColor: Colors.grey[400],
errorColor: Colors.red,
controller: _password,
obscureText: true,
hint: "Password",
validator: Validator.validatePassword,
);

i do like this
Widget customTextField(TextInputType textInputType) {
RegExp pattern = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+");
TextEditingController _textEditingController = TextEditingController();
if (textInputType == TextInputType.visiblePassword) {
return TextField(
controller: _textEditingController,
decoration: InputDecoration(hintText: 'Password'),
keyboardType: TextInputType.visiblePassword,
obscureText: true,
);
} else {
return TextField(
controller: _textEditingController,
decoration: InputDecoration(hintText: 'Email'),
keyboardType: TextInputType.emailAddress,
inputFormatters: [BlacklistingTextInputFormatter(pattern)],
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
shrinkWrap: true,
children: <Widget>[
customTextField(TextInputType.visiblePassword),
customTextField(TextInputType.emailAddress),
],
),
),
);
}
idk how to make RegExp for email, but the results will be like this:

class CustomTextFieldOutline extends StatefulWidget {
const CustomTextFieldOutline(
{Key key, this.hintText, this.label, this.onChange})
: super(key: key);
final String hintText;
final String label;
final void Function(String value) onChange;
#override
_CustomTextFieldOutlineState createState() => _CustomTextFieldOutlineState();
}
class _CustomTextFieldOutlineState extends State<CustomTextFieldOutline> {
bool showPassword = false;
TextEditingController controller = TextEditingController();
void _onChange(String value) {
controller.text = value;
if (widget.onChange != null) {
widget.onChange(value);
}
}
void _changePwdType() {
setState(() {
showPassword = !showPassword;
});
}
#override
Widget build(BuildContext context) {
return TextField(
obscureText: showPassword,
controller: controller,
onChanged: (value) => _onChange,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(showPassword ? Icons.visibility : Icons.visibility_off),
onPressed: _changePwdType,
),
hintText: widget.hintText != null ? widget.hintText : null,
labelText: widget.label != null ? widget.label : null,
),
);
}
}

You can try implement OutlineTextFormField Widget for Custom TextField of my company. I suppose it's pretty easy to extend, and it's include many utilities inside.
**
First, create outline_text_form_field.dart:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const int _defaultMinLinesOnMultiline = 6;
class OutlineTextFormField extends FormField<String> {
/// Creates a [FormField] that contains a [TextField].
///
/// 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 [initialValue] or the empty string.
///
/// For documentation about the various parameters, see the [TextField] class
/// and [new TextField], the constructor.
OutlineTextFormField({
Key? key,
required this.data,
bool updateStateIfInternalDataChanged = false,
this.controller,
String? initialValue,
FocusNode? focusNode,
InputDecoration? decoration,
String? hintText,
TextInputType? keyboardType,
TextCapitalization textCapitalization = TextCapitalization.none,
TextInputAction? textInputAction,
TextStyle? style,
StrutStyle? strutStyle,
TextDirection? textDirection,
TextAlign textAlign = TextAlign.start,
TextAlignVertical? textAlignVertical,
bool autofocus = false,
bool readOnly = false,
ToolbarOptions? toolbarOptions,
bool? showCursor,
String obscuringCharacter = '•',
bool obscureText = false,
bool autocorrect = true,
bool autoTrimWhenTyping = false,
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
bool enableSuggestions = true,
MaxLengthEnforcement? maxLengthEnforcement,
int maxLines = 1,
int? minLines, // when multiline = true, minLines = 6
bool expands = false,
int? maxLength,
bool multiline = false,
ValueChanged<String>? onChanged,
GestureTapCallback? onTap,
VoidCallback? onEditingComplete,
ValueChanged<String>? onFieldSubmitted,
FormFieldSetter<String>? onSaved,
FormFieldValidator<String>? validator,
List<TextInputFormatter>? inputFormatters,
bool? enabled,
double cursorWidth = 2.0,
double? cursorHeight,
Radius? cursorRadius,
Color? cursorColor,
Brightness? keyboardAppearance,
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
bool enableInteractiveSelection = true,
TextSelectionControls? selectionControls,
InputCounterWidgetBuilder? buildCounter,
ScrollPhysics? scrollPhysics,
Iterable<String>? autofillHints,
AutovalidateMode? autovalidateMode,
ScrollController? scrollController,
}) : assert(initialValue == null || controller == null),
assert(obscuringCharacter.length == 1),
assert(
maxLengthEnforcement == null,
'maxLengthEnforced is deprecated, use only maxLengthEnforcement',
),
assert(
(minLines == null) || (maxLines >= minLines),
"minLines can't be greater than maxLines",
),
assert(
!expands || minLines == null,
'minLines and maxLines must be null when expands is true.',
),
assert(!obscureText || maxLines == 1,
'Obscured fields cannot be multiline.'),
assert(maxLength == null || maxLength > 0),
super(
key: key,
initialValue: controller != null ? controller.text : initialValue,
onSaved: onSaved,
validator: validator,
enabled: enabled ?? decoration?.enabled ?? true,
autovalidateMode: autovalidateMode ??
(validator != null ? AutovalidateMode.onUserInteraction : null),
builder: (FormFieldState<String> field) {
if (updateStateIfInternalDataChanged &&
field.value != data) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
field.didChange(data);
});
}
final _OutlineTextFormFieldState state =
field as _OutlineTextFormFieldState;
final InputDecoration effectiveDecoration = InputDecoration(
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 15,
fontWeight: FontWeight.w400,
),
hintMaxLines: 2,
errorMaxLines: 2,
helperMaxLines: 2,
contentPadding: EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
filled: true,
fillColor: Colors.white,
floatingLabelBehavior: FloatingLabelBehavior.never,
).copyWith(hintText: hintText);
// .applyDefaults(Theme.of(field.context).inputDecorationTheme);
void onChangedHandler(String value) {
field.didChange(autoTrimWhenTyping ? value.trim() : value);
if (onChanged != null) {
onChanged(value);
}
}
return TextField(
controller: state._effectiveController,
focusNode: focusNode,
decoration:
effectiveDecoration.copyWith(errorText: field.errorText),
keyboardType: keyboardType,
textInputAction: textInputAction,
style: style ?? TextStyle(
color: Colors.black,
fontSize: 15,
fontWeight: FontWeight.w400,
),
strutStyle: strutStyle,
textAlign: textAlign,
textAlignVertical: textAlignVertical,
textDirection: textDirection,
textCapitalization: textCapitalization,
autofocus: autofocus,
toolbarOptions: toolbarOptions,
readOnly: readOnly,
showCursor: showCursor,
obscuringCharacter: obscuringCharacter,
obscureText: obscureText,
autocorrect: autocorrect,
smartDashesType: smartDashesType ??
(obscureText
? SmartDashesType.disabled
: SmartDashesType.enabled),
smartQuotesType: smartQuotesType ??
(obscureText
? SmartQuotesType.disabled
: SmartQuotesType.enabled),
enableSuggestions: enableSuggestions,
maxLengthEnforcement: maxLengthEnforcement,
maxLines: multiline ? null : maxLines,
minLines: minLines == null && multiline
? _defaultMinLinesOnMultiline
: minLines,
expands: expands,
maxLength: maxLength,
onChanged: onChangedHandler,
onTap: onTap,
onEditingComplete: onEditingComplete,
onSubmitted: onFieldSubmitted,
inputFormatters: inputFormatters,
enabled: enabled ?? decoration?.enabled ?? true,
cursorWidth: cursorWidth,
cursorHeight: cursorHeight,
cursorRadius: cursorRadius,
cursorColor: cursorColor,
scrollPadding: scrollPadding,
scrollPhysics: scrollPhysics,
keyboardAppearance: keyboardAppearance,
enableInteractiveSelection: enableInteractiveSelection,
selectionControls: selectionControls,
buildCounter: buildCounter,
autofillHints: autofillHints,
scrollController: scrollController,
);
},
);
/// Controls the text being edited.
///
/// If null, this widget will create its own [TextEditingController] and
/// initialize its [TextEditingController.text] with [initialValue].
final TextEditingController? controller;
late String data;
#override
_OutlineTextFormFieldState createState() => _OutlineTextFormFieldState();
}
class _OutlineTextFormFieldState extends FormFieldState<String> {
TextEditingController? _controller;
TextEditingController get _effectiveController =>
widget.controller ?? _controller!;
late StreamSubscription<String> dataStreamSubscription;
#override
OutlineTextFormField get widget => super.widget as OutlineTextFormField;
#override
void initState() {
super.initState();
if (widget.controller == null) {
_controller =
TextEditingController(text: widget.initialValue ?? widget.data);
}
setValue(widget.initialValue ?? widget.data);
_effectiveController.addListener(_handleControllerChanged);
dataStreamSubscription = Stream.value(widget.data).listen(_onData);
}
#override
void didUpdateWidget(OutlineTextFormField 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 =
TextEditingController.fromValue(oldWidget.controller!.value);
if (widget.controller != null) {
setValue(widget.controller!.text);
if (oldWidget.controller == null) _controller = null;
}
}
}
#override
void dispose() {
dataStreamSubscription.cancel();
_effectiveController.removeListener(_handleControllerChanged);
super.dispose();
}
#override
void didChange(String? value) {
super.didChange(value);
if (_effectiveController.text != value) {
_effectiveController.text = value ?? '';
_effectiveController.selection =
TextSelection.collapsed(offset: value?.length ?? 0);
}
widget.data = _effectiveController.text;
}
#override
void reset() {
// setState will be called in the superclass, so even though state is being
// manipulated, no setState call is needed here.
_effectiveController.text = widget.initialValue ?? widget.data;
super.reset();
}
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);
}
void _onData(String value) {
if (_effectiveController.text != value) _effectiveController.text = value;
}
}
** After you can use it:
String? validateStringBlank(
String? value,
String msg, [
bool autoToLowerCase = true,
]) =>
(value == null || value.trim().isEmpty)
? "Vui lòng nhập ${autoToLowerCase ? msg.toLowerCase() : msg}"
: null;
OutlineTextFormField(
data: "Apple",
hintText: "Enter company name",
validator: (value) =>
validateStringBlank(value,"Company Name"),
),

Related

Issue with textFormField/TextField triggering unnecessary rebuilds when focused

On focus, my textFormFields or textFields trigger unnecessary rebuilds, spike resource drains & make emulator & computer slow or even unusable. I've done considerable research on this. It seems like quite an issue & I haven't been able to resolve it.
What I've tried:
making form key a static final
=> static final GlobalKey<FormState> _signInFormKey = GlobalKey<FormState>();
using sizer instead of MediaQuery for dimensions
played around with calling field from ConsumerWidget, StatefulWidget, StatelessWidget, & ConsumerStatefulWidget
Nothing has worked so far.
Is there something I'm doing wrong?
Or is this the Flutter life of heated state management issues galore X 60hz refresh resource drain? :(
Here is the form field:
class CustomFormField extends StatefulWidget {
const CustomFormField({
Key? key,
required TextEditingController controller,
required bool prefixCurrencySymbol,
required String? currencySymbol,
required List<String> autoFillHints,
required bool blockSystemKeyboard,
required double width,
required FocusNode focusNode,
required TextInputType keyboardType,
required TextInputAction inputAction,
required String label,
required TextCapitalization textCapitalization,
required Function(String value) validator,
required bool obscurePasswordOption,
required bool saveAutofillData,
required bool passwordCreationField,
required Future<void> Function(String?)? onChanged,
}) : _formController = controller,
_prefixCurrencySymbol = prefixCurrencySymbol,
_currencySymbol = currencySymbol,
_autoFillHints = autoFillHints,
_blockSystemKeyboard = blockSystemKeyboard,
_width = width,
_formFocusNode = focusNode,
_keyboardType = keyboardType,
_inputAction = inputAction,
_textCapitalization = textCapitalization,
_label = label,
_validator = validator,
_obscurePasswordOption = obscurePasswordOption,
_saveAutofillData = saveAutofillData,
_passwordCreationField = passwordCreationField,
_onChanged = onChanged,
super(key: key);
final TextEditingController _formController;
final bool _prefixCurrencySymbol;
final String? _currencySymbol;
final List<String> _autoFillHints;
final bool _blockSystemKeyboard;
final double _width;
final FocusNode _formFocusNode;
final TextInputType _keyboardType;
final TextInputAction _inputAction;
final String _label;
final bool _obscurePasswordOption;
final TextCapitalization _textCapitalization;
final Function(String) _validator;
final bool _saveAutofillData;
final bool _passwordCreationField;
final Future<void> Function(String?)? _onChanged;
#override
State<CustomFormField> createState() => _CustomFormFieldState();
}
class _CustomFormFieldState extends State<CustomFormField> {
bool _obscurePassword = true;
#override
void dispose() {
widget._formFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget._width,
child: TextFormField(
style: ThemeEndpoints.textFieldTextStyle(),
autofillHints: widget._autoFillHints,
enableInteractiveSelection: true,
enableSuggestions: false,
autocorrect: false,
textAlignVertical: const TextAlignVertical(y: 0.1),
readOnly: widget._blockSystemKeyboard,
maxLines: 1,
controller: widget._formController,
focusNode: widget._formFocusNode,
keyboardType: widget._keyboardType,
obscureText: (widget._obscurePasswordOption) ? _obscurePassword : false,
textCapitalization: widget._textCapitalization,
textInputAction: widget._inputAction,
validator: (text) => widget._validator(text!),
onChanged: (text) => (widget._passwordCreationField && text.isNotEmpty)
? widget._onChanged!(text)
: null,
onEditingComplete:
(widget._saveAutofillData) ? () => TextInput.finishAutofillContext() : null,
toolbarOptions: const ToolbarOptions(
copy: true,
paste: true,
cut: true,
selectAll: true,
),
decoration: InputDecoration(
filled: true,
fillColor: ThemeEndpoints.textFieldBackgroundColor(),
alignLabelWithHint: true,
labelText: widget._label,
labelStyle: ThemeEndpoints.textFieldLabelStyle(),
contentPadding: const EdgeInsets.fromLTRB(32, 24, 12, 16),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
width: 0,
style: BorderStyle.none,
),
),
errorStyle: ThemeEndpoints.textFieldErrorTextStyle(),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
color: BrandColors.appLightRed,
width: 2,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
color: BrandColors.appRed,
width: 2,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
color: BrandColors.luckyLime,
width: 2,
),
),
prefixIconConstraints: (widget._prefixCurrencySymbol)
? const BoxConstraints(minWidth: 0, minHeight: 0)
: null,
prefixIcon: (widget._prefixCurrencySymbol)
? Container(
margin: const EdgeInsets.all(13),
child: Text(
widget._currencySymbol!,
style: ThemeEndpoints.textFieldCurrencySymbolTextStyle(),
),
)
: null,
suffixIcon: (widget._obscurePasswordOption)
? GestureDetector(
onTap: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
child: Container(
margin: const EdgeInsets.all(13),
child: _obscurePassword
? ThemeEndpoints.textFieldPasswordNotVisible()
: ThemeEndpoints.textFieldPasswordVisible(),
),
)
: null,
),
),
);
}
}
Here is my Form:
class SignInForm extends ConsumerWidget {
final FocusNode emailFocusNode;
final FocusNode passwordFocusNode;
SignInForm({
Key? key,
required this.emailFocusNode,
required this.passwordFocusNode,
}) : super(key: key);
final TextEditingController _email = TextEditingController();
final TextEditingController _password = TextEditingController();
static final GlobalKey<FormState> _signInFormKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context, WidgetRef ref) {
return AutofillGroup(
child: Form(
key: _signInFormKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
TextContent.of(context).authSignInText,
style: ThemeEndpoints.primaryHeader(),
),
const SizedBox(height: 16.0),
CustomFormField(
controller: _email,
onChanged: null,
prefixCurrencySymbol: false,
currencySymbol: null,
autoFillHints: const [AutofillHints.email],
blockSystemKeyboard: false,
width: 90.w,
focusNode: emailFocusNode,
keyboardType: TextInputType.emailAddress,
inputAction: TextInputAction.next,
label: TextContent.of(context).authFormEmailText,
textCapitalization: TextCapitalization.none,
validator: (email) => FormValidationUtility.emailFormValidator(
context,
email,
),
obscurePasswordOption: false,
saveAutofillData: false,
passwordCreationField: false,
),
const SizedBox(height: 16.0),
CustomFormField(
controller: _password,
onChanged: null,
prefixCurrencySymbol: false,
currencySymbol: null,
autoFillHints: const [AutofillHints.password],
blockSystemKeyboard: false,
width: 90.w,
focusNode: passwordFocusNode,
keyboardType: TextInputType.visiblePassword,
inputAction: TextInputAction.done,
label: TextContent.of(context).authFormPasswordText,
textCapitalization: TextCapitalization.none,
validator: (password) => FormValidationUtility.passwordGeneralValidator(
context,
password,
),
obscurePasswordOption: true,
saveAutofillData: false,
passwordCreationField: false,
),
const SizedBox(height: 64.0),
CustomButton(
buttonText: TextContent.of(context).authSignInText,
width: 50.w,
onPressed: () async => _onSignInPressed(
context,
ref,
[emailFocusNode, passwordFocusNode],
),
),
const SizedBox(height: 16.0),
const SignUpInkwell(),
const SizedBox(height: 16.0),
const SignInOptionsPulldown(),
],
),
),
);
}
// On pressed button execution
Future<void> _onSignInPressed(
BuildContext context,
WidgetRef ref,
List<FocusNode> focusNodes,
) async {
for (FocusNode node in focusNodes) {
node.unfocus();
}
if (_signInFormKey.currentState!.validate()) {
await ref.read(authenticationEndpoints).signIn(
context: context,
email: _email.text.trim(),
password: _password.text.trim(),
);
}
}
}
I just faced this issue last week, and found long discussion on github issue. but im forget to mark the issue, so i cant refer it.
there are 2 point that i get:
everytime focus triggered, the keyboard will appear on screen. this will trigger the screen to rebuild. Since numbers of the widget on screen was changed
there are behaviors in flutter, that when we have a nested StatefullWidget. here the question related: https://stackoverflow.com/a/50584602/12838877
in your case, you have parent statefullwidget, and some CustomTextField which is a statefull widget.
my workaround for my issue last week:
to avoid rebuild unnecessary widget every focus changed, i try to minimize use local method for all my widget. i choose to wrap into new StatelessWidget or StatefullWidget. This will not rebuild your entire widget tree.
then for the second problem, my solution is for every component that extends to StatefullWidget, i assign specific valueKey. even when i call setState and re-execute build method, since my valueKey is same, the widget will not rebuild.
like below
CustomFormField(
key: ValueKey('emailform'),
controller: _email,
onChanged: null,
....),
CustomFormField(
key: ValueKey('pswdForm'),
controller: pswd`,
onChanged: null,
....)

Flutter - Reusable Widget TextFormField - validation does not work

I am using a reusable widget and trying to pass a validation before the form is submitted.
But, I am not getting the error message that I should get. I have read the code several times, but do not find where is the problem. If you can have a quick look and tell me what I am missing it would be great.
import 'package:flutter/material.dart';
class TextFormFieldWidget extends StatefulWidget {
String hintText;
TextEditingController controller;
int maxLength;
int maxLines;
// Function onChanged;
TextInputAction? actionKeyboard;
String? parametersValidate;
String? defaultText;
String? labelText;
TextInputType? textInputType;
FocusNode? focusNode;
bool? obscureText;
Widget? prefixIcon;
Function onSubmitField;
Function? onFieldTap;
Function? functionValidate;
String? decoration;
String? validator;
//final dynamic Function(String?)? onChanged;
TextFormFieldWidget({
Key? key,
required this.hintText,
required this.controller,
required this.onSubmitField,
required this.maxLength,
required this.maxLines,
// required this.onChanged,
this.labelText,
this.validator,
this.parametersValidate,
this.textInputType,
this.onFieldTap,
this.defaultText,
this.actionKeyboard,
this.prefixIcon,
this.focusNode,
this.obscureText,
this.functionValidate,
this.decoration,
}) : super(key: key);
#override
_TextFormFieldWidgetState createState() => _TextFormFieldWidgetState();
}
class _TextFormFieldWidgetState extends State<TextFormFieldWidget> {
double bottomPaddingToError = 12;
#override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
primaryColor: Colors.black,
),
child: TextFormField(
cursorColor: Colors.black,
// obscureText: widget.obscureText,
keyboardType: widget.textInputType,
textInputAction: widget.actionKeyboard,
focusNode: widget.focusNode,
maxLength: widget.maxLength,
maxLines: widget.maxLines,
style: const TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.w200,
fontStyle: FontStyle.normal,
letterSpacing: 1.2,
),
initialValue: widget.defaultText,
decoration: InputDecoration(
prefixIcon: widget.prefixIcon,
hintText: widget.hintText,
// labelText: widget.decoration!,
// enabledBorder: const OutlineInputBorder(
// borderSide: BorderSide(color: Colors.black),
// ),
// focusedBorder: const OutlineInputBorder(
// borderSide: BorderSide(color: Colors.black),
// ),
hintStyle: const TextStyle(
color: Colors.grey,
fontSize: 14.0,
fontWeight: FontWeight.w300,
fontStyle: FontStyle.normal,
letterSpacing: 1.2,
),
contentPadding: EdgeInsets.only(
top: 12, bottom: bottomPaddingToError, left: 8.0, right: 8.0),
isDense: true,
errorStyle: const TextStyle(
color: Colors.red,
fontSize: 12.0,
fontWeight: FontWeight.w300,
fontStyle: FontStyle.normal,
letterSpacing: 1.2,
),
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedErrorBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
controller: widget.controller,
validator: (value) {
if (widget.functionValidate != null) {
String resultValidate =
widget.functionValidate!(value, widget.parametersValidate);
if (resultValidate != null) {
return resultValidate;
}
}
return null;
},
onFieldSubmitted: (value) {
if (widget.onSubmitField != null) widget.onSubmitField();
},
onTap: () {
if (widget.onFieldTap != null) widget.onFieldTap!();
},
),
);
}
}
String? commonValidation(String value, String messageError) {
var required = requiredValidator(value, messageError);
if (required != null) {
return required;
}
return null;
}
String? requiredValidator(value, messageError) {
if (value.isEmpty) {
return messageError;
}
return null;
}
void changeFocus(
BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}
Widget
Widget _buildTextFormField(String myHintText,TextEditingController myController,
int length,int lines,String myContent) {
return TextFormFieldWidget(
hintText: myHintText,
decoration: 'Test 33',
controller: myController,
maxLength: length,
maxLines: lines,
onSubmitField: () {},
validator:checkFieldEmpty( myContent),
);
String? checkFieldEmpty(String? fieldContent) { //<-- add String? as a return type
if(fieldContent!.isEmpty) {
return 'Field empty => Please, change this.';
}
return null;
View
SingleChildScrollView(
child: Form(
key: _addFirstTaskFormKey,
child: Column(
children: [
_buildTextFormField('Task Name',taskNameController,100,3,taskNameController.text),
ElevatedButton(
onPressed: (){
if(_addFirstTaskFormKey.currentState!.validate()){
print ('validated');
//taskItems.taskName = taskNameController.text;
//taskItems.notes = notesController.text;
}
}, child: const Text('Press'),
),
I think you're relatively new to flutter, don't worry I got you,
FormValidators are used to validate multiple fields declared inside a Form Widget.
Form widget uses a global Form key
declared Like this,
final _formKey = GlobalKey<FormState>();
and fields
Like this,
child: Form(child:Column(children:[
TextFormField(controller:controller),
TextFormField(controller:controller),
],),),
so when you need to validate fields just call,
_formKey.validate();
in the case above you are making a CustomTextFormField
you don't necessarily need to make it a stateful widget,
use StateLess Widget instead,
class CustomTextFormField extends StateLessWidget {
final TextInputType? keyboardType;
final TextEditingController? controller;
final FormFieldValidator<String>? validator;
final ValueChanged<String?>? onSaved;
final Function(String)? onChanged;
final VoidCallback? onTap;
const CustomTextFormField(
this.keyboardType,
this.controller,
this.validator,
this.onSaved,
this.onChanged,
this.onTap,
);
#override
Widget build(BuildContext context) {
return TextFormField(
keyboardType: keyboardType,
validator: validator,
autovalidateMode: autoValidateMode,
onSaved: onSaved,
onChanged: onChanged,
);
}
and use it like this
CustomTextFormField(
validator: (String? val) {
if(val==null) {
return "Value cannot be empty";
}
return null;
},
),
add any other validation that you may want to apply
and on save button call
if(_formKey.currentState.validate()) {
//SaveData
}else {
print("Validation Error")
}
This may be the problem. You're using null values. Flutter has Sound null safety so this means you can't set variables to null. I'm really curious, does your code even run?
Solution:
Scrap your validator and read through the Flutter Docs. They'll walk you through building a Form with validation here
validator: (value) {
if (widget.functionValidate != null) {
String resultValidate =
widget.functionValidate!(value, widget.parametersValidate);
if (resultValidate != null) {
return resultValidate;
}
}
return null;
},
onFieldSubmitted: (value) {
if (widget.onSubmitField != null) widget.onSubmitField();
},
onTap: () {
if (widget.onFieldTap != null) widget.onFieldTap!();
},
),
);
}

how to use inputFormatters and limit the characters of Textformfield with listener

I am using custom textFormField and custom keyboard's.
So In my custom TextFormField I want to set the maxlength to 16 and for every 4 characters I want to show some space (like our card Number).
I know how to use maxlength and inputFormatters to TextFormField but here I have to use listener for custom TextFormField.
controllerListener() {
widget.controller.addListener(() {
if (widget.type == KeyBoardType.CardNumberkeyBoard) {
regexValidationCardNumber(controller: widget.controller,length: 16);
}
}
regexValidationCardNumber({TextEditingController? controller, int? length}) {
if(controller != null && controller!.text.length > length!){
print("User trying to add more characters");
// maxlength 6
//inputFormatters
}
}
class CardNumberFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue previousValue,
TextEditingValue nextValue,
) {
var inputText = nextValue.text;
if (nextValue.selection.baseOffset == 0) {
return nextValue;
}
var bufferString = StringBuffer();
for (int i = 0; i < inputText.length; i++) {
bufferString.write(inputText[i]);
var nonZeroIndexValue = i + 1;
if (nonZeroIndexValue % 4 == 0 && nonZeroIndexValue != inputText.length) {
bufferString.write(' ');
}
}
var string = bufferString.toString();
return nextValue.copyWith(
text: string,
selection: TextSelection.collapsed(
offset: string.length,
),
);
}
}
page:
SizedBox(
width: width,
child: CommonTextFormField().textFormField(
controller: _preAuthProvider.cardNumberController,
hintText:
AppLocalizations.of(context)!.cardNumber,
isCenter: false,
// isReadOnly: true,
suffixIcon: const Padding(
padding: EdgeInsets.all(15),
child: Icon(Icons.credit_card),
),
onTap: () {
_preAuthProvider.showBottomKeyBoard(
context,
keyBoardType: KeyBoardType.CardNumberkeyBoard,
controller: _preAuthProvider.cardNumberController,
);
},
),
),
class CommonTextFormField {
Widget textFormField({
FieldType? type,
Widget? icon,
Widget? prefixIcon,
Widget? suffixIcon,
String? Function(String?)? validator,
TextStyle? style,
void Function()? onTap,
String? hintText,
String? labelText,
TextEditingController? controller,
String? initialValue,
double? contentPaddingVertical,
double? contentPaddingHorizontal,
Color? lineColor,
Function(String)? onChanged,
Function(String)? onFieldSubmitted,
bool hide = false,
bool isCenter = true,
bool isReadOnly = false,
bool isEnd = false,
bool enabled = true,
bool isMultiLine = false,
bool isCustomKeyBoard = false,
bool isBorderEnable = true,
bool isHintStyle = false,
bool isForSearch = true,
}) {
return TextFormField(
enabled: enabled,
readOnly: isReadOnly,
textInputAction: isForSearch ? TextInputAction.search : null,
controller: controller,
textAlign: type == FieldType.numericField ? TextAlign.end : isCenter ? TextAlign.center : isEnd ? TextAlign.justify
: TextAlign.start,
/* textAlign: isCenter
? TextAlign.center
: isEnd
? TextAlign.justify
: TextAlign.start,*/
style: style,
onFieldSubmitted: onFieldSubmitted,
onChanged: onChanged,
onTap: onTap,
cursorWidth: 0,
cursorHeight: 0,
validator: validator,
obscureText: hide,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
CardNumberFormatter(),
],
maxLength: 8,
minLines: (type == FieldType.notesLine && isMultiLine ) ? 3 :null,
maxLines: (type == FieldType.notesLine && isMultiLine ) ? 5 : 1,
//minLines: isMultiLine ? 3 : null,
//maxLines: isMultiLine ? 5 : 1,
keyboardType: isMultiLine
? TextInputType.multiline
: isCustomKeyBoard
? TextInputType.none
: TextInputType.text,
decoration: InputDecoration(
counterText: "",
prefixIcon: type == FieldType.numericField
? const Padding(
padding:
EdgeInsets.symmetric(vertical: 15, horizontal: 10),
child: Text("\$"),
)
: null,
/*prefixIcon: icon != null
? Padding(
padding: const EdgeInsets.symmetric(vertical: 15,horizontal: 10),
child: icon,
)
: null,*/
suffixIcon: suffixIcon,
isDense: true,
labelText: (type == FieldType.labelField || type == FieldType.notesLine || type == FieldType.numericField
) ? labelText:null,
//labelText: labelText,
contentPadding: EdgeInsets.symmetric(
horizontal: contentPaddingHorizontal ?? 0,
vertical: contentPaddingVertical ?? 15),
border: const OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: isBorderEnable
? lineColor ?? Colors.white
: Colors.transparent)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: isBorderEnable
? lineColor ?? Colors.white
: Colors.transparent)),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: isBorderEnable
? lineColor ?? Colors.white
: Colors.transparent)),
hintText: hintText,
labelStyle: const TextStyle(
color: Colors.white,
),
hintStyle: isHintStyle ? TextStyle(color: Colors.white) : TextStyle(color: Colors.grey.withOpacity(0.5)),
floatingLabelAlignment: FloatingLabelAlignment.start,
),
);
}
}
controller:
/// showBottomKeyBoard(context, { controller }) => show bottom keyBoard
showBottomKeyBoard(
BuildContext context, {
TextEditingController? controller,
KeyBoardType keyBoardType = KeyBoardType.DOUBLEZERO,
}) {
showKeyBoard(context,
controller: controller!,
backGroundColor: Theme.of(context).backgroundColor,
buttonSize: 90,
keyBoardType: keyBoardType);
}
But I want this with listener.

How can I change the position of the Textformfield validation text ? Flutter

I made a custom form and when I want to use the validation. My issue is that the error message is not appearing as I wanted. Here's the screenshot of it.
So I want to change the position of the error message to be below my container. Does anyone have any idea how to do it ?
Here's the code of the form:
class AuthForm extends StatefulWidget {
final bool isPassword;
final IconData prefixIcon;
final String hintText;
late bool isPasswordVisible = isPassword;
final bool isCalendar;
final TextEditingController controller;
final bool isDropDown;
final bool isPhone;
final String? Function(String?)? validator;
AuthForm({Key? key, this.isPassword = false, required this.prefixIcon, required this.hintText,
this.isCalendar = false, required this.controller, this.isDropDown = false, this.isPhone = false, required this.validator}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
#override
void initState() {
super.initState();
if (widget.isPhone){
getCountryCode();
}
}
start () async {
await CountryCodes.init();
}
Locale? getCountryCode () {
start();
final Locale? deviceLocale = CountryCodes.getDeviceLocale();
final CountryDetails details = CountryCodes.detailsForLocale();
return deviceLocale;
}
DateTime selectedDate = DateTime(2000,1);
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
width: 70.w,
height: 5.h,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.13.w,
color: Theme.of(context).splashColor,
),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
widget.prefixIcon,
color: Theme.of(context).primaryColor,
size: 6.w,
),
widget.isDropDown ? const DropDownBar() :
Expanded(
child: TextFormField(
//autovalidateMode: AutovalidateMode.onUserInteraction,
validator: widget.validator,
keyboardType: widget.isPhone ? TextInputType.phone : TextInputType.text,
inputFormatters: [DialCodeFormatter()],
controller: widget.controller,
textAlign: TextAlign.center,
obscureText: widget.isPasswordVisible,
style: Theme.of(context).textTheme.bodyText2,
decoration: InputDecoration(
hintText : widget.hintText,
hintStyle: Theme.of(context).textTheme.bodyText1,
border: InputBorder.none,
),
onTap: () async {
if (widget.isCalendar){
//Dismiss the keyboard
FocusScope.of(context).requestFocus(FocusNode());
//Call the calendar
await _selectDate(context);
widget.controller.text = DateFormat('dd-MM-yyyy').format(selectedDate);
}
}
),
),
//Show Icon only if the form is for a Password
Visibility(
visible: widget.isPassword,
//Maintain the space where the widget is even if it is hid
maintainAnimation: true,
maintainState: true,
maintainSize: true,
child: InkWell(
highlightColor : Colors.transparent,
splashColor: Colors.transparent,
child: Icon(
widget.isPasswordVisible ? Icons.visibility : Icons.visibility_off,
color: Theme.of(context).primaryColor,
size: 6.w,
),
onTap: () {
setState(() {
widget.isPasswordVisible = !widget.isPasswordVisible;
});
},
),
),
],
),
);
}
}
Thanks for your suggestion,
Chris
You should try below piece of code for TextFormField
TextFormField(
textInputAction: TextInputAction.next,
style: TextStyle(fontSize: 16, height: 1),
inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10)],
keyboardType: TextInputType.phone,
validator: (val) {
if (val!.isEmpty) {
return 'Please enter your mobile number';
} else if (val.length < 10) {
return 'Mobile number should be 10 digits only';
}
},
controller: bloc.mobileNumberLoginController,
decoration: InputDecoration(
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide(
color: code != null ? HexColor(code!) : Colors.pink,
)),
contentPadding: EdgeInsets.only(top: 5, bottom: 5, left: 10, right: 10),
),
),

Implementation Outlined text field Input with lable text in flutter application

i want to have a textFieldInput with border that has label inside the border like the image below. Thankyou in advance
TextField(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: "Label",
hintText: "Input Text",
contentPadding: EdgeInsets.fromLTRB(32, 16, 32, 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
Result:
I think you want to achieve something like this.
Inactive
Active
Validation
You can achieve this design by using this widget.
class OutlineBorderTextFormField extends StatefulWidget {
FocusNode myFocusNode;
TextEditingController tempTextEditingController;
String labelText;
TextInputType keyboardType;
bool autofocus = false;
TextInputAction textInputAction;
List<TextInputFormatter> inputFormatters;
Function validation;
bool checkOfErrorOnFocusChange = false;//If true validation is checked when evre focus is changed
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _OutlineBorderTextFormField();
}
OutlineBorderTextFormField(
{#required this.labelText,
#required this.autofocus,
#required this.tempTextEditingController,
#required this.myFocusNode,
#required this.inputFormatters,
#required this.keyboardType,
#required this.textInputAction,
#required this.validation,
#required this.checkOfErrorOnFocusChange});
}
class _OutlineBorderTextFormField extends State<OutlineBorderTextFormField> {
bool isError = false;
String errorString = "";
getLabelTextStyle(color) {
return TextStyle(
fontSize: 12.0, color: color
);
} //label text style
getTextFieldStyle() {
return TextStyle(
fontSize: 12.0,
color: Colors.black,
);
} //textfield style
getErrorTextFieldStyle() {
return TextStyle(
fontSize: 10.0,
color: Colors.red,
);
}// Error text style
getBorderColor(isfous) {
return isfous
? Colors.deepPurple
: Colors.black54;
}//Border colors according to focus
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 16.0, top: 15.0, right: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FocusScope(
child: Focus(
onFocusChange: (focus) {
//Called when ever focus changes
print("focus: $focus");
setState(() {
getBorderColor(focus);
if (widget.checkOfErrorOnFocusChange &&
widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
} else {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
}
});
},
child: Container(
padding: EdgeInsets.all(2.0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(
6.0) // <--- border radius here
),
border: Border.all(
width: 1,
style: BorderStyle.solid,
color: isError
? Colors.red
: getBorderColor(widget.myFocusNode.hasFocus),
)),
child: TextFormField(
focusNode: widget.myFocusNode,
controller: widget.tempTextEditingController,
style: getTextFieldStyle(),
autofocus: widget.autofocus,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
inputFormatters: widget.inputFormatters,
validator: (string) {
if (widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
setState(() {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
return "";
} else {
setState(() {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
}
return null;
},
decoration: InputDecoration(
labelText: widget.labelText,
labelStyle: isError
? getLabelTextStyle(
Colors.red)
: getLabelTextStyle(Colors.deepPurple),
contentPadding:
EdgeInsets.symmetric(vertical: 7, horizontal: 16),
fillColor: Colors.grey[200],
filled: true,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
border: InputBorder.none,
errorStyle: TextStyle(height: 0),
focusedErrorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hasFloatingPlaceholder: true),
),
),
),
),
Visibility(
visible: isError ? true : false,
child: Container(
padding: EdgeInsets.only(left: 15.0, top: 2.0),
child: Text(
errorString,
style: getErrorTextFieldStyle(),
))),
],
),
);
;
}
}
Example for calling this widget
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
FocusNode myFocusNode = new FocusNode();
TextEditingController tempTextEditingController = TextEditingController();
FocusNode myFocusNode1 = new FocusNode();
TextEditingController tempTextEditingController1 = TextEditingController();
void validateAndSave() {
final FormState form = _formKey.currentState;
if (form.validate()) {
print('Form is valid');
} else {
print('Form is invalid');
}
}
String getTempIFSCValidation(String text) {
return text.length > 5 ? "* Please enter valid IFSC Code" : "";
}
String getTempAccountValidation(String text) {
return text.length > 8 ? "* Please enter valid Account Number" : "";
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
OutlineBorderTextFormField(labelText: "Account Number*",myFocusNode: myFocusNode,tempTextEditingController: tempTextEditingController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
return getTempAccountValidation(textToValidate);
},),
OutlineBorderTextFormField(labelText: "Re- Enter Account Number*",myFocusNode: myFocusNode1,tempTextEditingController: tempTextEditingController1,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
print("Value Validated");
return getTempIFSCValidation(textToValidate);
},),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: validateAndSave,//call the validation method
tooltip: 'Validate',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}