Text field update doesn't work with flutter_masked_text - dart

I'm creating a app, where one of the features is update text fields
based on changes of another text fields.
The fields are about product prices in: Dollar, Euro, Real.
If the price in Dollar are changed by user, the Euro and Real price are too, and so on...
The problem is, if I use the normal TextEditingController all works well, but if I use MoneyMaskedTextController from the flutter_masked_text package, the updating stops.
Could any one test my code and to answer me why the updating stops with the MoneyMaskedTextController?
To test, don't forget to install the flutter_masked_text: ^0.8.0 in your pubspec.yaml.
If I can not use the flutter_masked_text for it, how could I use masks and update text fields?
Thank you.
import 'package:flutter/material.dart';
import 'package:flutter_masked_text/flutter_masked_text.dart';
void main() {
runApp(MaterialApp(
home: ProductType(),
));
}
class ProductType extends StatefulWidget {
_ProductTypeScreen createState() => _ProductTypeScreen();
}
class _ProductTypeScreen extends State<ProductType> {
#override
Widget build(BuildContext context) {
double dollarRate = 3.70;
double euroRate = 4.20;
//Normal controllers
/* final ctrl_real = TextEditingController();
final ctrl_dollar = TextEditingController();
final ctrl_euro = TextEditingController();*/
//Money Mask controllers
final ctrl_real = MoneyMaskedTextController();
final ctrl_dollar = MoneyMaskedTextController();
final ctrl_euro = MoneyMaskedTextController();
void change_real(String text) {
double real = double.parse(text);
ctrl_dollar.text = (real / dollarRate).toString();
ctrl_euro.text = (real / euroRate).toString();
}
void change_dollar(String text) {
double dolar = double.parse(text);
ctrl_real.text = (dolar * dollarRate).toString();
ctrl_euro.text = (dolar * dollarRate / euroRate).toString();
}
void change_euro(String text) {
double euro = double.parse(text);
ctrl_real.text = (euro * euroRate).toString();
ctrl_dollar.text = (euro * euroRate / dollarRate).toString();
}
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: 160.0,
height: 200.0,
padding: EdgeInsets.all(20.0),
child: TextField(
controller: ctrl_euro,
decoration: InputDecoration(
labelText: "Euro price",
prefixText: "€"),
onChanged: change_euro,
keyboardType: TextInputType.numberWithOptions(
decimal: true),
)),
Container(
width: 160.0,
height: 200.0,
padding: EdgeInsets.all(20.0),
child: TextField(
controller: ctrl_dollar,
decoration: InputDecoration(
labelText: "Dolar price",
prefixText: "US\$"),
onChanged: change_dollar,
keyboardType: TextInputType.numberWithOptions(
decimal: true),
)),
Container(
width: 160.0,
height: 200.0,
padding: EdgeInsets.all(20.0),
child: TextField(
controller: ctrl_real,
decoration: InputDecoration(
labelText: "Real price",
prefixText: "R\$"),
onChanged: change_real,
keyboardType: TextInputType.numberWithOptions(
decimal: true),
)),
]
)
)
);
}
}

If you check the value received on each method , you will see a comma "," in your decimal values.
void change_real(String text) {
print("Text : $text");
}
so every time you try to parse those values , it crashes here:
double real = double.parse(text);
One way to solve your issue just change the decimalSeparator to '.' , like this:
final ctrl_real = MoneyMaskedTextController(decimalSeparator: ".");
final ctrl_dollar = MoneyMaskedTextController(decimalSeparator: ".");
final ctrl_euro = MoneyMaskedTextController(decimalSeparator: ".");

Related

How to pass an event Type to a widget with block pattern?

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))
...
)

[Flutter/Dart]: How to dynamically change the keyboard type for a TextFormField in a Form?

I have a Widget that renders a ListView of TextFormFields to input data. However, I want to change the keyboard type for one of my textfields dynamically. Here is an overview of the Widget:
class CreateTodo extends StatefulWidget {
#override
_CreateTodoState createState() => _CreateTodoState();
}
class _CreateTodoState extends State<CreateTodo> {
final _formKey = GlobalKey<FormState>();
final double formWidth = 175.0;
final Map<String, Icon> itemsMap = {
'Heading': Icon(Icons.title),
'Description': Icon(Icons.edit),
'Date': Icon(Icons.calendar_today)
};
final items = ['Heading', 'Description', 'Date'];
_changeKeyboardType(entry) {
if (entry == "Description") {
return TextInputType.multiline;
}
return TextInputType.text;
}
ListView createListItems() {
return ListView.builder(
padding: EdgeInsets.only(
left: 50.0,
right: 50.0,
top: 20.0
),
scrollDirection: Axis.vertical,
itemCount: 3,
itemBuilder: (context, index) {
var currentHeading = this.items[index];
var currentIcon = this.itemsMap[currentHeading];
return Padding(
padding: EdgeInsets.only(bottom: 50.0),
child: new TextFormField(
validator: (input) {
if (input.isEmpty) {
return 'You must enter a ${currentHeading.toLowerCase()} for your to-do';
}
},
keyboardType: this._changeKeyboardType(currentHeading),
decoration: new InputDecoration(
prefixIcon: currentIcon,
labelText: currentHeading,
border: OutlineInputBorder(),
),
)
);
}
);
}
#override
Widget build(BuildContext context) {
return Form(
autovalidate: true,
child: Expanded(
child: (this.createListItems())
)
);
}
}
The main line that isn't working is: keyboardType: this._changeKeyboardType(currentHeading) ... Am I approaching this problem the wrong way? Any direction will be super helpful. I basically want the textFormFeld for the description being multiline so users can have a better visualization of their description.
My working solution for now:
// Where entry is an object containing its focusNode and textInputType
entry.focusNode.unfocus();
setState(() {
entry.textInputType = type;
});
// The delay was necessary, otherwise only the 2nd tap would actually change
Future.delayed(const Duration(milliseconds: 1), () {
FocusScope.of(context).requestFocus(entry.focusNode);
});
Only downside I couldn't fix so far is that the keyboard is disappearing before it re-appears with the new TextInputType.
Google's Spreadsheet app does it instantaneous without the close, would love to know if and how that'll be doable in Flutter.
You'd have to change your logic as my example is asynchronous.
Let me know if that helps or if you need more help.
Or, if you've already figured it out, how you did it
May like this:
Credits: It's inspired by https://stackoverflow.com/a/58498474/3484824

Auto-validate Issue : Password and Confirm Password validation with autovalidation in Flutter

I have created Form Widget in that form there are multiple TextFormFeild which i created custom BoxFeild . I am facing problem related to auto-validation from Form Widget. Unable to validate password matching feild in confirm password BoxFeild
Should i validate password matching after formKeyData saved in current state ?
I am facing issue when passing key to BoxFeild constructor. Its showing multiple widgets used the same global key.
I need to add global FormFeild key to compare _password and _confirmPassword.
class _PageSignUpState extends State<PageSignUp> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
var passKey = GlobalKey<FormFieldState>();
bool _autoValidate = false;
String _name, _email, _phoneNo, _password, _confirmPassoword;
bool isLoading = false;
final _passwordController = TextEditingController();
final _confirmPassController = TextEditingController();
double width,height;
#override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: Colors.white,
body: Container(
color: Colors.grey.shade200,
child: Center(
child: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Form(
key: _formKey,
autovalidate: _autoValidate,
child: Column(
children: <Widget>[
_nameWidget(),
_emailWidget(),
_passwordWidget(),
_confirmPassWidget(),
SizedBox(height: height/25),
_signUpButtonWidget()
],
)),
],
),
),
),
),
),
);
}
Container _signUpButtonWidget() {
return Container(
padding: EdgeInsets.symmetric(vertical: height / 40, horizontal: width / 15),
width: double.infinity,
child: RaisedButton(
padding: EdgeInsets.all(12.0),
child: Text(
"Sign Up",
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
color: Colors.blue,
onPressed: () {
setLoading(true);
_validateInputs();
},
),
);
}
BoxFeild _confirmPassWidget() {
return BoxFeild(
hintText: "Confirm Password",
lableText: "Confirm Password",
obscureText: true,
icon: Icons.lock_outline,
validator: validatePasswordMatching,
onSaved: (String val) {
_confirmPassoword = val;
},
);
}
BoxFeild _passwordWidget() {
return BoxFeild(
key: passKey,
hintText: "Enter Password",
lableText: "Password",
obscureText: true,
icon: Icons.lock_outline,
controller: _passwordController,
validator: validatePassword,
onSaved: (String val) {
_password = val;
},
);
}
BoxFeild _emailWidget() {
return BoxFeild(
hintText: "Enter Email",
lableText: "Email",
keyboardType: TextInputType.emailAddress,
icon: Icons.email,
validator: validateEmail,
onSaved: (String val) {
_email = val;
},
);
}
BoxFeild _nameWidget() {
return BoxFeild(
hintText: "Enter Name",
lableText: "Name",
icon: Icons.person,
validator: validateName,
onSaved: (String val) {
_name = val;
},
);
}
String validateName(String value) {
String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = RegExp(patttern);
if (value.length == 0) {
return "Name is Required";
} else if (!regExp.hasMatch(value)) {
return "Name must be a-z and A-Z";
}
return null;
}
String validateEmail(String value) {
RegExp regExp = RegExp(Constants.PATTERN_EMAIL, caseSensitive: false);
if (value.length == 0) {
return "Email is Required";
} else if (!regExp.hasMatch(value)) {
return "Enter valid email address.";
}
return null;
}
String validatePassword(String value) {
if (value.length == 0) {
return "Password is Required";
} else if (value.length < 6) {
return "Password Should be more than 6.";
}
return null;
}
String validatePasswordMatching(String value) {
var password = passKey.currentState.value;
if (value.length == 0) {
return "Password is Required";
} else if (value != password) {
return 'Password is not matching';
}
return null;
}
void _validateInputs() {
if (_formKey.currentState.validate()) {
//If all data are correct then save data to out variables
//Make a REST Api Call with success Go to Login Page after User Created.
_formKey.currentState.save();
setLoading(true);
Utils.checkConnection().then((connectionResult) {
if (connectionResult) {
} else {
setLoading(false);
Utils.showAlert(context, "Flutter",
"Internet is not connected. Please check internet connection.",
() {
Navigator.pop(context);
}, true);
}
});
}
} else {
// If all data are not valid then start auto validation.
setState(() {
_autoValidate = true;
});
}
}
}
BoxFeild.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BoxFeild extends StatefulWidget {
final TextEditingController controller;
final FocusNode focusNode;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final TextCapitalization textCapitalization;
final TextStyle style;
final TextAlign textAlign;
final bool autofocus;
final bool obscureText;
final bool autocorrect;
final int maxLines;
final Key key;
final int maxLength;
final bool maxLengthEnforced;
final ValueChanged<String> onChanged;
final VoidCallback onEditingComplete;
final ValueChanged<String> onSubmitted;
final List<TextInputFormatter> inputFormatters;
final bool enabled;
final IconData icon;
final String hintText;
final String lableText;
final double cursorWidth;
final Radius cursorRadius;
final Color cursorColor;
final Color defaultBorderColor;
final Brightness keyboardAppearance;
final EdgeInsets scrollPadding;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
final FormFieldSetter<String> onSaved;
const BoxFeild({
this.key,
this.controller,
this.focusNode,
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.icon,
this.textAlign = TextAlign.start,
this.autofocus = false,
this.obscureText = false,
this.autocorrect = true,
this.maxLines = 1,
this.maxLength,
this.onSaved,
this.hintText,
this.lableText,
this.maxLengthEnforced = true,
this.onChanged,
this.defaultBorderColor,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.keyboardAppearance,
this.scrollPadding,
this.validator,
this.onFieldSubmitted,
}) : assert(textAlign != null),
assert(autofocus != null),
assert(obscureText != null),
assert(autocorrect != null),
assert(maxLengthEnforced != null),
assert(maxLines == null || maxLines > 0),
assert(maxLength == null || maxLength > 0),
keyboardType = keyboardType ??
(maxLines == 1 ? TextInputType.text : TextInputType.multiline);
#override
_BoxFeildState createState() => _BoxFeildState();
}
class _BoxFeildState extends State<BoxFeild> {
double width;
double height;
Color focusBorderColor = Colors.grey.shade400;
FocusNode _focusNode = FocusNode();
ValueChanged<Colors> focusColorChange;
#override
void dispose() {
super.dispose();
_focusNode.dispose();
}
#override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width;
height = MediaQuery.of(context).size.height;
return Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: width / 30,
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: height / 400, bottom: height / 400, left: width / 50, right: width / 50),
padding: EdgeInsets.all(height / 100),
alignment: Alignment.center,
height: height / 14,
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border.all(color: focusBorderColor, width: 1.0),
borderRadius: BorderRadius.circular(8.0)),
child: TextFormField(
key: this.widget.key,
obscureText: this.widget.obscureText,
onSaved: this.widget.onSaved,
validator: this.widget.validator,
onFieldSubmitted: this.widget.onFieldSubmitted,
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Icon(
this.widget.icon,
size: height/34,
),
hintText: this.widget.hintText),
),
)),
],
),
padding: EdgeInsets.only(bottom : height / 58),
margin: EdgeInsets.only(
top: height / 50, right: width / 20, left: width / 30),
);
}
}
Now If, I am using different Container for password feild then its working. And If I am passing key and controller to boxfeild then its show
multiple widgets used the same global key
Container _passwordWidget() {
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
height: 52.0,
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border.all(color: Colors.transparent, width: 0.0),
borderRadius: BorderRadius.circular(12.0)),
child: TextFormField(
key: passKey,
obscureText: true,
validator: validatePassword,
onSaved: (String val) {
_password = val;
},
keyboardType: TextInputType.number,
style: TextStyle(
fontSize: 22.0,
color: Colors.black,
),
decoration:
InputDecoration.collapsed(hintText: "Password"),
),
);
}
You are declaring the passkey in a wrong way use final Globalkey instead of var

Capture data from TextFormField on flutter for http POST request

i am trying to make a login with flutter.
I am consulting a web service.
I want to send in the body of the Post request the username and the password from different TextFormField. how can i do that?
Here is the code i've been working on.
import 'package:flutter/material.dart';
import 'package:device_id/device_id.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
class SignIn extends StatefulWidget {
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
Future<String> getData() async {
final response = await http.post(
Uri.encodeFull("The route i'm consulting),
body: {
"username": user,
"password": password
},
I want to retrieve the input texts from username and password TextFormField below in here
headers: {
"Accept": "application/json",
});
print(response.statusCode);
print(response.body);
}
String _deviceid = 'Unknown';
String user = '';
String password = '';
TextEditingController controller = new TextEditingController();
TextEditingController controller2 = new TextEditingController();
#override
void dispose() {
controller.dispose();
controller2.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
username = TextFormField(
This is the first TextFormField i want to retrieve to send it in the body of the request
controller: controller,
keyboardType: TextInputType.text,
autofocus: false,
decoration: InputDecoration(
hintText: "Username",
hintStyle: TextStyle(fontSize: 16.0),
contentPadding: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 10.0),
border:
UnderlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final password = TextFormField(
This is the second TextFormField i want to retrieve to send it in the body of the request
controller: controller2,
autofocus: false,
obscureText: true,
decoration: InputDecoration(
hintText: "Password",
hintStyle: TextStyle(fontSize: 16.0),
contentPadding: EdgeInsets.fromLTRB(20.0, 25.0, 20.0, 10.0),
border:
UnderlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 25.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
shadowColor: Colors.blueAccent.shade100,
elevation: 10.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
color: Colors.blueAccent,
onPressed: (){
},
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
),
),
);
return Form(
child: new Center(
child: ListView(
padding: EdgeInsets.only(left: 24.0, right: 24.0, top: 10.0),
children: <Widget>[
username,
SizedBox(height: 8.0),
password,
SizedBox(height: 24.0),
loginButton
]),
),
);
}
}
See Retrieve the value of a text field.
Wrap a StatefulWidget around your form
Add two TextEditingController fields in your State, one for each TextFormField
Pass the controllers to your form fields (controller constructor parameter)
Retrieve the values, for example in a button click listener using myController.text
I'm not sure if you are also asking how to send a HTTP post request.
Here is a very minimal example:
class LoginScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextFormField(controller: _usernameController,),
TextFormField(controller: _passwordController, obscureText: true,),
RaisedButton(
onPressed: _performLogin,
child: Text('Login'),
)
],
);
}
void _performLogin() {
String username = _usernameController.text;
String password = _passwordController.text;
print('login attempt: $username with $password');
}
}
Here is a full example of a login Screen ... where you can validate inputs and submit the data after passing the validation.
import 'package:flutter/material.dart';
import '../mixins/validate_mixin.dart';
class LoginScreen extends StatefulWidget{
final GlobalKey<ScaffoldState> scaffoldKey;
LoginScreen(this.scaffoldKey);
#override
State<StatefulWidget> createState() {
return LoginScreenState(scaffoldKey);
}
}
class LoginScreenState extends State<LoginScreen> with ValidateMixin{
final formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> scaffoldKey;
LoginScreenState(this.scaffoldKey);
String _email;
String _password;
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(40.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
emailField(),
passwordField(),
Container(margin: EdgeInsets.only(bottom: 25.0),),
submitButton(),
],
),
),
);
}
Widget emailField() {
return TextFormField(
decoration: InputDecoration(hintText: 'ali#gmail.co', labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: validateEmail,
onSaved: (String value) {
_email = value;
},
);
}
Widget passwordField() {
return TextFormField(
obscureText: true,
decoration: InputDecoration(hintText: '*****', labelText: 'Password'),
onSaved: (String value) {
_password = value;
},
);
}
Widget submitButton() {
return RaisedButton.icon(
color: Colors.cyan[900],
textColor: Colors.white,
label: Text('Submit'),
icon: Icon(Icons.save),
onPressed: () {
final bool v = formKey.currentState.validate();
if (v) {
formKey.currentState.save();
_performLogin();
print('object');
}
},);
}
void _performLogin () {
var snackbar = new SnackBar(
content: Text('Email: $_email and Password $_password'),
);
scaffoldKey.currentState.showSnackBar(snackbar);
}
}
You can back to the full example.
https://github.com/anbturki/flutter_login_screen

Detect Keyboard event in Flutter

How to detect keyboard events on TextFormField in Flutter? If the user deletes the last letter and presses the delete button again, the cursor should jump back to the previous TextFormField.
I would like to implement a pin-enter screen, something like that one.
https://mobile-solutions.ingenico.com/wp-content/uploads/IMG_022.png
Yes you can do that using onChange And FocusScope for set focus
Here when you delete last letter of second FormField focus set on first FormField
var firstField = FocusNode();
var secondField = FocusNode();
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
TextFormField(
focusNode: firstField,
onChanged: (text) {
print("First field: $text");
},
),
TextFormField(
focusNode: secondField,
onChanged: (text) {
if (text.length <= 0) {
FocusScope.of(context).requestFocus(firstField);
}
print("Second field: $text");
},
)
]);
}
To implement pin-enter screen, You don't have to manage the Keyboard events. As that screen has different button and each button does the entry as its text.
So logically you just have to add the value of the button to the list and remove the value from the list when delete key is pressed.
You can fill the TextField with the length and data of the list.
I hope this answer helps you. I faced a similar situation and this is how I did it!
class _OtpEntryFormState extends StatelessWidget {
final _formKey = GlobalKey<FormState>();
//Declare your focusNodes
FocusNode node1 = FocusNode();
FocusNode node2 = FocusNode();
FocusNode node3 = FocusNode();
FocusNode node4 = FocusNode();
String pin1;
String pin2;
String pin3;
String pin4;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
//Now create a row widget, where we'll be adding our textboxes
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//TextBox1
SizedBox(
width: 50,
child: TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(1),
],
focusNode: node1,
onChanged: (text) {
if (text.length == 1) {
FocusScope.of(context).requestFocus(node2);
pin1 = text;
}
},
keyboardType: TextInputType.number,
)
),
//Spacing in-between textbox
SizedBox(
width: 20
),
//TextBox2
SizedBox(
width: 50,
child: TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(1),
],
focusNode: node2,
onChanged: (text) {
if (text.length == 1) {
FocusScope.of(context).requestFocus(node3);
pin2 = text;
}
else if (text.isEmpty) {
FocusScope.of(context).requestFocus(node1);
}
},
keyboardType: TextInputType.number,
)
),
//Spacing in-between textbox
SizedBox(
width: 20
),
//TextBox3
SizedBox(
width: 50,
child: TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(1),
],
focusNode: node3,
onChanged: (text) {
if (text.length == 1) {
FocusScope.of(context).requestFocus(node4);
pin3 = text;
}
else if (text.isEmpty) {
FocusScope.of(context).requestFocus(node2);
}
},
)
),
//Spacing in-between textbox
SizedBox(
width: 20
),
//TextBox4
SizedBox(
width: 50,
child: TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(1),
],
focusNode: node4,
onChanged: (text) {
if (text.length == 1) {
FocusScope.of(context).requestFocus(node4);
pin4 = text;
}
else if (text.isEmpty) {
FocusScope.of(context).requestFocus(node3);
}
},
)
),
],
),
//Spacing Between the textbox row and the submit button
SizedBox(
height: 10,
),
//Submit Button
SizedBox(
width: 30,
child: RaisedButton(
color: Colors.blueAccent,
textColor: Colors.white,
onPressed: () {
if (_formKey.currentState.validate()) {
String fullPin = pin1+pin2+pin3+pin4;
String combinedPin = fullPin;
int intPin = int.parse(combinedPin);
print("OPT Pin: " + intPin.toString());
}
},
child:
Text(
'SUBMIT',
)
),
),
],
);
}
}

Resources