Related
I'm building a form for shipping and am able to add as many items as possible. (Adding a Widget in a ListView every time a button is pressed)
My question is, once the form widgets are created and filled, how do I get the information from each TextFormField in each Widget?
Once the information is retrieved I will send it to Firebase.
Here's the code I Have:
import 'package:flutter/material.dart';
import 'package:flutter_login_test/helpers/constants.dart';
class AddItemsToRequest extends StatefulWidget {
const AddItemsToRequest({Key? key}) : super(key: key);
#override
State<AddItemsToRequest> createState() => _AddItemsToRequestState();
}
class _AddItemsToRequestState extends State<AddItemsToRequest> {
List<TextEditingController> controllers = [];
List<Widget> fields = [];
RegExp regExp = RegExp('[aA-zZ]');
int quantity = 0;
double weight = 0;
double height = 0;
Widget itemForm() {
return Column(children: [
Container(
decoration:
BoxDecoration(color: grey, border: Border.all(color: black)),
width: double.infinity,
child: const Center(
child: Text('Package details',
style: TextStyle(
fontWeight: FontWeight.bold,
backgroundColor: grey,
fontSize: 24)),
)),
Row(
children: [
Flexible(
child: TextFormField(
onChanged: (value) {
quantity = value as int;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || value is int
? 'Quantity cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Quantity : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
weight = value as double;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || regExp.hasMatch(value)
? 'Weight cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Weight : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
height = value;
},
validator: (value) => value!.isEmpty ? 'Height cannot be empty' : null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Height : "),
),
),
],
),
]);
}
Widget _addTile() {
return ElevatedButton(
child: const Icon(Icons.add),
onPressed: () async {
final controller = TextEditingController();
final field = itemForm();
setState(() {
controllers.add(controller);
fields.add(field);
});
});
}
Widget _listView() {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: fields.length,
itemBuilder: (context, index) {
final item = fields[index];
return Dismissible(
key: ObjectKey(item),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
fields.removeAt(index);
});
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Package removed')));
},
background: Container(
color: const Color.fromARGB(255, 210, 31, 19),
child: const Center(
child: Text(
'Remove ',
style: TextStyle(
color: white, fontWeight: FontWeight.bold, fontSize: 32),
),
)),
child: Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: fields[index],
),
);
},
);
}
Widget _okButton() {
return ElevatedButton(
onPressed: () {
for (var element in fields) {
print(quantity);
}
Navigator.of(context).pop();
print('ok');
},
child: const Text("OK"),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: blue),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(child: _addTile()),
SizedBox(
height: MediaQuery.of(context).size.height - 200,
child: _listView()),
Flexible(child: _okButton()),
],
),
);
}
}
I think you are expecting this answer. iterate your list of texteditingcontroller and get the text stored in that controllers one by one.
for (int i = 0; i < controllers.length; i++) {
var data = controllers[i].text;
//print or add data to any other list and insert to another list and save to database
}
so i have a text field in witch the user will enter the password and i want to display at the end that icon if the user click on it it will show the password else it's going to hidden . the text field is inside the container basically as shown in the picture . How to do it ?
Container(
height: MediaQuery.of(context).size.height * 0.08,
margin: const EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: const Color(0xFFEFEDED),
border: Border.all(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(
children: [
Icon(Icons.remove_red_eye_outlined),
TextFormField(
controller: controller,
keyboardType:
isUrl ? TextInputType.url : TextInputType.text,
decoration: const InputDecoration(
border: InputBorder.none,
),
),
],
),
),
)
,
The following code enable and toggles the show/hide text by pressing the "eye" button on the far right.
It works with a boolean variable.
Remember to have a Stateful Widget.
bool hidden;
#override
void initState() {
hidden = true;
super.initState();
}
TextFormField(
controller: controller,
obscureText: hidden,
keyboardType: isUrl ? TextInputType.url : TextInputType.text,
decoration: InputDecoration(
border: InputBorder.none,
suffixIcon: IconButton(
onPressed: () => setState(() {
hidden = !hidden;
}),
icon: const Icon(Icons.remove_red_eye_outlined))),
)
I'm working on phone number textfield, so for i got this package, and i want its CustomDecoration style, but i'm not getting it. here is my code.
Widget phonetextformfieldCustomwithouticon(context, width, controller, height) {
return Container(
width: width,
child: InternationalPhoneNumberInput(
inputDecoration: InputDecoration(
contentPadding:EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
},
),
);
}
updated:
I want country should have some padding, becuase it starts from the leftmost, and when i add validation in it, redner flow
Container(
width: MediaQuery.of(context).size.width * 0.9,
height: 55.0,
decoration: BoxDecoration(
border: Border.all(color: HexColor("#6e6b7b")),
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
child: InternationalPhoneNumberInput(
inputDecoration: InputDecoration(
contentPadding:EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0),
labelText: "Phone number",
labelStyle: GoogleFonts.montserrat(color: HexColor("#6e6b7b")),
hintStyle: GoogleFonts.montserrat(),
hintText: "Enter a phone number",
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 0.0,
))),
// enabledBorder: InputBorder.none,
onInputChanged: (PhoneNumber number) {
print(number.phoneNumber);
},
onInputValidated: (bool value) {
print(value);
},
selectorConfig: SelectorConfig(
selectorType: PhoneInputSelectorType.DIALOG,
),
ignoreBlank: false,
autoValidateMode: AutovalidateMode.disabled,
selectorTextStyle: TextStyle(color: Colors.black),
// initialValue: number,
textFieldController: contactNo,
formatInput: false,
keyboardType: TextInputType.numberWithOptions(
signed: true, decimal: true),
inputBorder: InputBorder.none,
onSaved: (PhoneNumber number) {
print('On Saved: $number');
},
),
),
here is the output:
Try below code hope its helpful to you.refer package here and example here
create variables:
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
final TextEditingController controller = TextEditingController();
String initialCountry = 'NG';
PhoneNumber number = PhoneNumber(isoCode: 'NG');
Create one function for getting number and dispose your controller
void getPhoneNumber(String phoneNumber) async {
PhoneNumber number =
await PhoneNumber.getRegionInfoFromPhoneNumber(phoneNumber, 'US');
setState(() {
this.number = number;
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
Your widget:
Container(
padding: EdgeInsets.all(7),
color: Colors.blue,
child: Card(
child: Form(
key: formKey,
child: Container(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InternationalPhoneNumberInput(
onInputChanged: (PhoneNumber number) {
print(number.phoneNumber);
},
onInputValidated: (bool value) {
print(value);
},
selectorConfig: SelectorConfig(
selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
),
ignoreBlank: false,
autoValidateMode: AutovalidateMode.disabled,
selectorTextStyle: TextStyle(color: Colors.black),
initialValue: number,
textFieldController: controller,
formatInput: false,
keyboardType: TextInputType.numberWithOptions(
signed: true, decimal: true),
inputBorder: InputBorder.none,
onSaved: (PhoneNumber number) {
print('On Saved: $number');
},
),
],
),
),
),
),
),
Your result screen on your need->
I've just written this:
InternationalPhoneNumberInput(
onInputChanged: (val) {},
inputDecoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 0.0,
),
),
enabledBorder: InputBorder.none,
),
),
and it seems like these:
But I couldn't test it on android. Can you try this?
I'm working on a TextFormField to accept passwords. I have set the suffix icon to have IconButton child to detect on click events and to toggle the obscuretext attribute of the TextFormField. The callback function for the iconButton gets called but the TextFormField doesn't get repainted. Any ideas on how to solve this?
static Widget buildTextFormField(String id,
FormFieldValidator<String> validateField,
FormFieldSetter<String> saveField,
InputDecoration decoration,
EdgeInsetsGeometry paddingInfo,
EdgeInsetsGeometry marginInfo,
TextInputType keyboardType,
{bool obscureField:false, double width:328.0,
TextEditingController controller}
){
return Container(
padding: paddingInfo,
margin: marginInfo,
width: width,
child: TextFormField(
key: Key(id),
obscureText: obscureField,
validator: validateField,
onSaved: saveField,
keyboardType: keyboardType,
decoration: decoration,
controller: controller,
),
);
}
InputDecoration passwordDecoration = InputDecoration(
hintText: 'Password',
labelText: 'Enter your password',
suffixIcon:
IconButton(
icon: Icon(
_passwordVisible ? Icons.visibility : Icons.visibility_off,
semanticLabel: _passwordVisible ? 'hide password' : 'show password',
),
onPressed: () {
setState(() {
_passwordVisible ^= true;
//print("Icon button pressed! state: $_passwordVisible"); //Confirmed that the _passwordVisible is toggled each time the button is pressed.
});
}),
labelStyle: TextStyle(
fontFamily: 'Roboto Medium',
fontSize: 12.0,
color: Color(0x99000000),
letterSpacing: 0.4,
),
);
final passwordPaddingInfo = const EdgeInsets.only(top: 15.0, bottom:15.0,
left: 22.0, right:25.0);
this._passwordField = AdministrationComponents.
buildTextFormField('passwordField', validatePassword,
(value) => _password = value, passwordDecoration, passwordPaddingInfo,
null, null, controller:_passwordController,
obscureField: !_passwordVisible);
Try to this
bool _showPassword = false;
void _togglevisibility() {
setState(() {
_showPassword = !_showPassword;
});
}
Textform field code
child: TextFormField(
controller: _passwordController,
obscureText: !_showPassword,
cursorColor: Colors.red,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Password",
border: InputBorder.none,
suffixIcon: GestureDetector(
onTap: () {
_togglevisibility();
},
child: Icon(
_showPassword ? Icons.visibility : Icons
.visibility_off, color: Colors.red,),
),
),
),
Show/Hide Passwords in Flutter's TextFormField
Step 1:
bool _obscureText = true;
Step 2:
void _toggle() {
setState(() {
_obscureText = !_obscureText;
});
}
Step 3:
TextField(
controller: password,
style: TextStyle(fontSize: 16.0),
obscureText: _obscureText,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
hintText: "Password",
suffixIcon: InkWell(
onTap: _toggle,
child: Icon(
_obscureText
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
size: 15.0,
color: Colors.black,
),
),
),
),
Thanks #ShyjuM and # diegoveloper! I see what I was doing wrong - I was calling the buildTextFormField in the constructor of my State class and not in the build method. Moving the call to buildTextFormField inside the build method fixed it. Thanks again for all of your help!
You have some errors in your code.
Replace this :
_passwordVisible > Icons.visibility : Icons.visibility_off,
and
_passwordVisible ^= true;
By this:
_passwordVisible ? Icons.visibility : Icons.visibility_off,
and
_passwordVisible = !_passwordVisible;
This is the Password dart i use
import 'package:flutter/material.dart';
class LoginPass extends StatefulWidget {
LoginPass(this.controllerUpass);
final Function controllerUpass;
#override
_LoginPassState createState() => _LoginPassState();
}
class _LoginPassState extends State<LoginPass> {
bool _isHidden = true;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 30, 0, 10),
child: Container(
height: 35,
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: TextField(
obscureText: _isHidden,
onChanged: (value) {
widget.controllerUpass(value);
},
decoration: InputDecoration(
hintText: 'Password',
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
suffixIcon: GestureDetector(
onTap: () {
setState(() {
_isHidden = !_isHidden;
});
},
child: _isHidden
? Icon(
Icons.remove_red_eye_sharp,
color: Colors.blue,
)
: Icon(
Icons.remove_red_eye,
color: Colors.red,
),
)),
),
),
),
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black26,
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 3),
),
],
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(3)),
),
),
);
}
}
In Main call
LoginPass(controllerUpass),
How to customise TextField's width and height?
To adjust the width, you could wrap your TextField with a SizedBox widget, like so:
const SizedBox(
width: 100.0,
child: TextField(),
)
I'm not really sure what you're after when it comes to the height of the TextField but you could definitely have a look at the TextStyle widget, with which you can manipulate the fontSize and/or height
const SizedBox(
width: 100.0,
child: TextField(
style: TextStyle(fontSize: 40.0, height: 2.0, color: Colors.black),
),
)
Bear in mind that the height in the TextStyle is a multiplier of the font size, as per comments on the property itself:
The height of this text span, as a multiple of the font size.
When [height] is null or omitted, the line height will be determined
by the font's metrics directly, which may differ from the fontSize.
When [height] is non-null, the line height of the span of text will be a
multiple of [fontSize] and be exactly fontSize * height logical pixels
tall.
Last but not least, you might want to have a look at the decoration property of you TextField, which gives you a lot of possibilities
EDIT: How to change the inner padding/margin of the TextField
You could play around with the InputDecoration and the decoration property of the TextField. For instance, you could do something like this:
const TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(vertical: 40.0),
),
)
I think you want to change the inner padding/margin of the TextField.
You can do that by adding isDense: true and contentPadding: EdgeInsets.all(8) properties as follow:
Container(
padding: EdgeInsets.all(12),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Default TextField',
),
),
SizedBox(height: 16,),
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Densed TextField',
isDense: true, // Added this
),
),
SizedBox(height: 16,),
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Even Densed TextFiled',
isDense: true, // Added this
contentPadding: EdgeInsets.all(8), // Added this
),
)
],
),
)
It will be displayed as:
Screenshot:
You can do it in many ways:
Using maxLines + expands:
SizedBox(
width: 240, // <-- TextField width
height: 120, // <-- TextField height
child: TextField(
maxLines: null,
expands: true,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(filled: true, hintText: 'Enter a message'),
),
)
Using just maxLines:
Widget _buildTextField() {
final maxLines = 5;
return Container(
margin: EdgeInsets.all(12),
height: maxLines * 24.0,
child: TextField(
maxLines: maxLines,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(filled: true, hintText: 'Enter a message'),
),
);
}
This answer works, but it will have conflicts when the input field is in error state, for a better approach and a better control you can use this.
InputDecoration(
isCollapsed: true,
contentPadding: EdgeInsets.all(9),
)
If you want to increase the height of TextFormField dynamically while typing the text in it. Set maxLines to null. Like
TextFormField(
onSaved: (newText) {
enteredTextEmail = newText;
},
obscureText: false,
keyboardType: TextInputType.emailAddress,
validator: validateName,
maxLines: null,
// style: style,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(5.0, 10.0, 5.0, 10.0),
hintText: "Enter Question",
labelText: "Enter Question",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0))),
),
Wrap TextField in SizedBox for the width
SizedBox(
height: 40,
width: 150,
child: TextField(),
)
You can try the margin property in the Container. Wrap the TextField inside a Container and adjust the margin property.
new Container(
margin: const EdgeInsets.only(right: 10, left: 10),
child: new TextField(
decoration: new InputDecoration(
hintText: 'username',
icon: new Icon(Icons.person)),
)
),
If you use "suffixIcon" to collapse the height of the TextField add:
suffixIconConstraints
TextField(
style: TextStyle(fontSize: r * 1.8, color: Colors.black87),
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(vertical: r * 1.6, horizontal: r * 1.6),
suffixIcon: Icon(Icons.search, color: Colors.black54),
suffixIconConstraints: BoxConstraints(minWidth: 32, minHeight: 32),
),
)
simply wrap the TextField() in SizedBox() and give the height of the sized box
use contentPadding, it will reduce the textbox or dropdown list height
InputDecorator(
decoration: InputDecoration(
errorStyle: TextStyle(
color: Colors.redAccent, fontSize: 16.0),
hintText: 'Please select expense',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(1.0),
),
contentPadding: EdgeInsets.all(8)),//Add this edge option
child: DropdownButton(
isExpanded: true,
isDense: true,
itemHeight: 50.0,
hint: Text(
'Please choose a location'), // Not necessary for Option 1
value: _selectedLocation,
onChanged: (newValue) {
setState(() {
_selectedLocation = newValue;
});
},
items: citys.map((location) {
return DropdownMenuItem(
child: new Text(location.name),
value: location.id,
);
}).toList(),
),
),
Set minLines: null, maxLines: null and expands:true to let the TextField fill the height of its parent widget:
Container(
child: TextField(
minLines: null,
maxLines: null,
expands: true
)
)
Refere to these docs for the same:https://api.flutter.dev/flutter/material/TextField/expands.html
And for width, you can do this:
Container(
width: 100,
child: TextField(
)
)
to let the TextField fill its parent widget's width(100 pixels in this case)
Adjust Height using contentPadding instead of SizeBox or Container
Container(
width: width * 0.85,
child: TextFormField(
textInputAction: TextInputAction.next,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(vertical: 10), //Imp Line
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
width: 0.5,
color: Constants.secondaryColourLight,
)),
),),)
80k ka code hein 80k ka
Finally, I got my solution using this trick.
Provide Height and width of sizedbox and set expand the property to true. Also, set maxLines to null and minLines to null.
SizedBox(
height: SizeConfig.screenWidth * 0.1377,
child: TextFormField(
validator: validator,
enabled: isEnabled,
expands: true,
maxLines: null,
minLines: null,
),
);
TextField( minLines: 1, maxLines: 5, maxLengthEnforced: true)
int numLines = 0;
Container(
height: numLines < 7 ? 148 * WidgetsConstant.height: numLines * WidgetsConstant.height * 24,
child: TextFormField(
controller: _bodyText,
maxLines: numLines < 7 ? 148 : numLines,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
onChanged: (String value) {
setState(() {
numLines = '\n'.allMatches(value).length + 1;
});
},
),
),
The perfect way to get rid of padding is to use InputDecoration.collapsed.
It wraps the GestureDetector with a Container and decorates the Container with as much Padding, Border, and Decoration as needed.
GestureDetector(
onTap: () => _focusNode.requestFocus(),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(4),
),
child: TextField(
focusNode: _focusNode,
decoration: const InputDecoration.collapsed(
hintText: 'Search...',
border: OutlineInputBorder(
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
),
),
),
);
To display an icon, change the Container child to Row, and use Icon and a TextField wrapped with Expanded.
To increase the height of TextField Widget just make use of the maxLines: properties that comes with the widget. For Example:
TextField(
maxLines: 5
) // it will increase the height and width of the Textfield.
You can simply wrap Text field widget in padding widget.....
Like this,
Padding(
padding: EdgeInsets.only(left: 5.0, right: 5.0),
child: TextField(
cursorColor: Colors.blue,
decoration: InputDecoration(
labelText: 'Email',
hintText: 'xyz#gmail.com',
//labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(width: 2, color: Colors.blue,)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(width: 2, color: Colors.green)),
)
),
),
You can change max
minLines: 4,
maxLines: 6,
Provide a maxLines and add a BoxConstraints with width and height in InputDecoration.
TextField(
maxLines: 10,
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
constraints: BoxConstraints.tightFor(width: 300, height: 100),
),
);
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
constraints: BoxConstraints(maxHeight:48,maxWidth: 327,),
),
);