so in my TextFormField widgets, I have set the TextInputAction to TextInputAction.next, I have also defined the focusNodes and onFieldSubmitted callbacks.
One of the Text fields:
TextFormField(
keyboardType: TextInputType.number,
maxLength: 2,
validator: (value)=> value.isEmpty ? "Birth Month" : null,
onSaved: (value)=> _birthMonth = value,
textInputAction: TextInputAction.next,
focusNode: _birthMonthFocus,
onFieldSubmitted: (v) =>FocusScope.of(context).requestFocus(_birthYearFocus)
)
The code above works. However, the icons aren't changing. I have ran it on 3 different emulators now, and it's still the same thing.
Try this code..
final FocusNode _nameFocus = FocusNode();
final FocusNode _id = FocusNode();
void _fieldFocusChange(
BuildContext context, FocusNode nameFocus, FocusNode passwordFocus) {
nameFocus.unfocus();
FocusScope.of(context).requestFocus(passwordFocus);
}
// below code define text field.
textInputAction: TextInputAction.next,
focusNode: _id,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _id, _nameFocus);
},
Related
I'm trying to create an app with block pattern and flutter_block library. It is working, but now I want to reduce the code.
I have a lot of:
dart
Padding(
padding:
EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
child: TextField(
inputFormatters: [
BlacklistingTextInputFormatter(RegExp("[a-zA-Z]"))
],
decoration: InputDecoration(
labelText: 'label text'),
keyboardType: TextInputType.number,
controller: _service,
onChanged: (value) =>
{_prefsBloc.dispatch(SetServicePrefs(value))},
),
),
I'm transforming that in a widget:
dart
class SettingTextField extends StatelessWidget {
final String text;
final String labelText;
SettingTextField({this.text, this.labelText});
#override
Widget build(BuildContext context) {
final PrefsBloc _prefsBloc = BlocProvider.of<PrefsBloc>(context);
final TextEditingController _controller = TextEditingController();
_controller.text = this.text;
if (this.text != null) {
_controller.selection = TextSelection.collapsed(offset: this.text.length);
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
child: TextField(
inputFormatters: [BlacklistingTextInputFormatter(RegExp("[a-zA-Z]"))],
decoration: InputDecoration(labelText: this.labelText),
keyboardType: TextInputType.number,
controller: _controller,
onChanged: (value) {}
);
}
}
For each field, I have a different event to dispatch to block like:
_prefsBloc.dispatch(SetServicePrefs(value))
But I really don't know how to pass the type SetServicePrefs to my widget and use it in the onChanged function.
How do I solve this problem?
You can add additional callback field to SettingTextField:
class SettingTextField extends StatelessWidget {
final String text;
final String labelText;
final Function(PrefsBloc bloc, value) onChanged;
...
TextField(
inputFormatters: [BlacklistingTextInputFormatter(RegExp("[a-zA-Z]"))],
decoration: InputDecoration(labelText: this.labelText),
keyboardType: TextInputType.number,
controller: _controller,
onChanged: (value) => onChanged(_prefsBloc, value)
)
...
}
Then call SettingTextField:
SettingTextField(
...
onChanged: (bloc, value) => bloc.dispatch(SomeEventType(value))
...
)
The TextField should be changed, if the String - Variable is changed from some other method.
The text box should therefore receive an update if the user enters a new text or the associated variable has been changed from another location.
//Calling new text boxes
new eingabeTextbox(false, "Bemerkungen", "...", (String str){zahlerBemerkungen = str; print("neuer Bemerkungswert:" + str);},zahlerBemerkungen),
//paged class to avoid source code redundancy
class eingabeTextbox extends StatelessWidget {
final bool _nummerischeTastatur;
final String _ueberschrift;
final String _platzhalter;
ValueChanged<String> eingegebenerWert;
ValueChanged<String> variableUeberwachen;
eingabeTextbox(this._nummerischeTastatur, this._ueberschrift, this._platzhalter, this.eingegebenerWert, this.variableUeberwachen);
#override
Widget build (BuildContext context){
return new TextField(
keyboardType: _nummerischeTastatur == true ? TextInputType.number : TextInputType.multiline,
decoration: new InputDecoration(
labelText: _ueberschrift,
hintText: _platzhalter
),
onSubmitted: eingegebenerWert,
onChanged: variableUeberwachen
);
}
}
My approach with "ValueChanged variableUeberwachen;" does not work.
Can someone help me?
I made a custom input widget by wrapping Textfield in some widgets and so on. Now I can't reach the onChanged property directly from the custom widget. I tried making a property in my custom widget but couldn't implement it properly. I googled passing variables between widgets and it seems a hard thing to do. Any simple solution?
class Input extends StatelessWidget {
final String text;
final TextInputType type;
final int maxLength;
final bool password;
final String label;
final IconData icon;
final double padding;
final Function onChanged;
final ColorSwatch color;
Input(
{this.type = TextInputType.text,
#required this.text,
this.maxLength,
this.icon,
this.padding = 0.0,
this.password = false,
#required this.onChanged,
this.label,
this.color});
final String value = '';
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(padding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.all(3.0),
child: Text(
text + ":",
style: TextStyle(fontSize: 15.0, color: color),
),
),
Container(
padding: EdgeInsets.all(3.0),
width: 300.0,
child: TextField(
obscureText: password,
decoration: InputDecoration(
labelText: label,
icon: Icon(icon),
),
maxLength: maxLength,
keyboardType: type,
textInputAction: TextInputAction.next,
onChanged: onChanged,
),
),
],
),
);
}
}
You need to provide onChanged and other events in your custom widget, even if you are just providing these to the underlying TextField. In other words, you need to pass the onChanged function down through your custom widget.
For example:
MyAwesomeTextField extends StatelessWidget {
/// Callback for being notified of changes to the text field
/// This should have a proper type, I'm just using Function for simplicity
final Function onChanged;
// Make the onChanged property settable through the constructor
MyAwesomeTextField({this.onChanged});
Widget build(BuildContext context) {
// Construct your widget tree, and pass your onChanged function through
return TextField(onChanged: this.onChanged);
}
}
Then when you're using it, your custom widget will have an onChanged event:
...
MyCustomWidget(onChanged: (value) => print(value) )
...
I have a weird problem in flutter TextFormField. I implemented form validation in TextFormField. But onSaved() function doesn't get called after successful validation.
First I created basic Widget using TextFormField
--- In AppWidgets class ---
static Widget buildTextFormField(
String labelText,
String helperText,
IconData prefixIcon, {
Widget suffixIcon,
bool obscureText = false,
TextInputType keyboardType = TextInputType.text,
TextInputAction textInputAction = TextInputAction.none,
FocusNode focusNode,
ValueChanged<String> onFieldSubmitted,
TextEditingController controller,
FormFieldValidator<String> validator,
FormFieldSetter<String> onSaved,
bool isLightTheme = false,
}) {
return Theme(
data: isLightTheme
? AppThemesLight.textFormFieldThemeData
: AppThemesDark.textFormFieldThemeData,
child: TextFormField(
controller: controller,
validator: validator,
onSaved: onSaved,
keyboardType: keyboardType,
textInputAction: textInputAction,
focusNode: focusNode,
onFieldSubmitted: onFieldSubmitted,
obscureText: obscureText,
decoration: InputDecoration(
filled: true,
fillColor: isLightTheme
? AppColorsLight.textFieldFillColor
: AppColorsDark.textFieldFillColor,
labelText: labelText,
helperText: helperText,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(AppDimensions.textFieldBorderRadius),
),
),
prefixIcon: Icon(
prefixIcon,
color: isLightTheme
? AppColorsLight.primaryTextColor
: AppColorsDark.primaryTextColor,
),
suffixIcon: suffixIcon,
),
),
);
}
From that, created email text from field.
static Widget buildEmailTextFormField(LoginState loginState) {
return AppWidgets.buildTextFormField(
'Email address',
'Your email address',
Icons.email,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
focusNode: loginState.focusNodes[0],
onFieldSubmitted: (String value) {
print('submitted $value');
loginState.onFocusChanged(index: 0);
},
validator: (String email) {
print('validator $email');
return InputValidators.validateEmail(email);
},
onSaved: (String email) {
print('saved $email');
loginState.email = email;
},
);
}
Here is the email validator I used.
static String validateEmail(String email) {
Pattern pattern =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = new RegExp(pattern);
if (email.isEmpty)
return 'Email can\'t be empty';
else if (!regex.hasMatch(email))
return 'Enter valid email address';
else
return null;
}
I tested above code by putting print statement inside onSaved() function, but it's not printing after successful validation.
The onSaved() function won't be called automatically after successful validation. We have to call _formKey.currentState.save() manually to save our variables.
Form(
key: key,
child: TextFormField(
onSaved: (val) {
print('saved');
},
validator: (val) {
print('validating');
},
),
),
RaisedButton(
child: Text('Click me'),
onPressed: () {
if (key.currentState.validate()) {
key.currentState.save();
print('valid');
}
},
),
Did you call this method formKey.currentState.save() ?
in my case i forgot to call this after adding this it has worked.
Is there a way in dart language to keep the maximum input length fixed in TextFormField?
Use inputFormatters property. The following code would limit the textFormField to 42 in length :
new TextFormField(
inputFormatters: [
new LengthLimitingTextInputFormatter(42),
],
);
UPDATE: Import the package first. import 'package:flutter/services.dart';
use maxLength
TextFormField(
controller: _deskripsiController,
onFieldSubmitted: (String value){
setState(() {
_deskripsiController.text = value;
});
},
decoration: const InputDecoration(
border: const UnderlineInputBorder(),
labelText: "Deskripsi",
),
maxLength: 8,
)
best way is inputFormatters option:
inputFormatters: [
new LengthLimitingTextInputFormatter(11),// for mobile
],
Additionally to hahnsaja answer after you add maxLength - counter appears at the bottom of the TextFormField widget. To be able to hide it, add this to InputDecoration :
counterText: '',
counterStyle: TextStyle(fontSize: 0),
Example:
TextFormField(
controller: _deskripsiController,
onFieldSubmitted: (String value){
setState(() {
_deskripsiController.text = value;
});
},
decoration: const InputDecoration(
border: const UnderlineInputBorder(),
labelText: "Deskripsi",
counterText: '',
counterStyle: TextStyle(fontSize: 0),
),
maxLength: 8,
)