Related
class login extends StatelessWidget {
var emailController = TextEditingController();
var PasswordController = TextEditingController();
var _formKey = GlobalKey<FormState>();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Center(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Login",
style: TextStyle(
fontSize: 40, fontWeight: FontWeight.bold)),
SizedBox(height: 40,),
TextFormField(
controller: emailController,
onFieldSubmitted: (String value) {
print(value);
},
onChanged: (String value) {
print(value);
},
validator: (String ?value) {
if (value == null || value.isEmpty) {
return 'the password must not be Empty';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "E-mail Address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
prefixIcon: Icon(Icons.email),
),
),
SizedBox(height: 20,),
TextFormField(
controller: PasswordController,
obscureText: true,
keyboardType: TextInputType.visiblePassword,
validator: (String ?value) {
if (value == null || value.isEmpty) {
return 'the password must not be Empty';
}
return null;
},
onFieldSubmitted: (String value) {
print(value);
},
onChanged: (String value) {
print(value);
},
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
prefixIcon: Icon(Icons.lock),
suffixIcon: Icon(Icons.remove_red_eye_rounded)
)
),
SizedBox(height: 20,),
defaultButton(
background: Colors.black26,
isUpperCase: true,
text: "Login",
function: () {
if (_formKey.currentState!.validate()) ==> // Null check operator
used on a null value.
{
print(emailController);
print(PasswordController);
}
}
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Already you Have account?"),
TextButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => Registry()));
},
child: Text("Register now "))
],
),
],
),
),
),
),
),
);
}
}
Hey what you're using is called the non-null assertion operator, it actually means you are saying that value can't be null. If you want to make sure it's not null before trying to access validate(), you should use optional chaining _formKey.currentState?.validate()
What you can also try to do is check that it's not null before you call validate().
if (!!_formkey.currentState && _formKey.currentState.validate())
This the form where I'm trying to move the focus. All is working fine till the field title, where I want to move it to a textField phone number but in doing so instead of moving the focus the soft keyboard disappears. I tried to attached scrollController to the SingleScrollView and then move it in onSaved in the textfield before this one I want to get focus:
controller.singleSclollViewController.jumpTo(controller.singleSclollViewController.position.maxScrollExtent);
But it is doing nothing.
This is the complete form with that problem
Form(
key: controller.formKey,
child: SingleChildScrollView(
controller: controller.singleSclollViewController,
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
verticalSpaceMedium,
Image.asset(
'assets/graphics/data.png',
),
Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: GetBuilder<HomeController>(
builder: (builderController) =>
builderController.isPosition
? CustomTextField(
autofocus: true,
focusNode:
controller.adressFocusNode,
validate: (text) => controller
.validateTextField(text),
maxline: 4,
minLine: 2,
height: 80.h,
width: 0.8.sw,
controller:
controller.adressController,
color:
AppColors.primaryColorShade,
//adress
lableText: 'адреса',
)
: CircularProgressIndicator()),
),
verticalSpaceSmall,
Container(
padding: EdgeInsets.symmetric(
horizontal: 40,
vertical: 10,
),
child: TypeAheadFormField<City>(
validator: (text) {
if (globalController
.doesSuggestionExist) {
//there is no such available city
return 'такого доступного міста немає';
}
return controller
.validateTextField(text ?? '');
},
textFieldConfiguration:
TextFieldConfiguration(
controller: controller.cityController,
decoration:
outlineInputTextFormFieldStyle!
.copyWith(
label: Text(
//city
'місто',
style: textfieldLableStyle,
)),
),
onSuggestionSelected: (City city) {
controller.cityController.text =
city.name;
controller.nameFocusNode.requestFocus();
},
itemBuilder: (_, City city) {
return ListTile(
leading: Icon(Icons.location_city),
title: Text(
city.name,
style: headingBlackStyle,
),
);
},
suggestionsCallback: (pattern) async {
return await globalController
.getSuggestions(pattern, '');
}),
),
verticalSpaceSmall,
OneLineTextField(
focusNode: controller.nameFocusNode,
onSubmit: () {
controller.nameFocusNode.unfocus();
controller.titleFocusNode.requestFocus();
},
keybordhType: TextInputType.name,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//name/"Ім'я та прізвище"
lable: "Ім'я та прізвище",
maxLenght: 25,
controller: controller.nameController),
verticalSpaceSmall,
OneLineTextField(
onSubmit: () {
controller.singleSclollViewController
.jumpTo(controller
.singleSclollViewController
.position
.maxScrollExtent);
controller.phoneFocusNode.requestFocus();
},
focusNode: controller.titleFocusNode,
maxLenght: 25,
keybordhType: TextInputType.name,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//title/"потрібен титул"
lable: 'Назва оголошення',
controller: controller.titleController),
verticalSpaceSmall,
OneLineTextField(
focusNode: controller.phoneFocusNode,
onSubmit: () => controller
.descripotionFocusNode
.requestFocus(),
maxLenght: 15,
keybordhType: TextInputType.number,
validator: (text) {
return controller
.validateTextField(text ?? '');
},
//phone number/ "телефонний номер"
lable: 'телефонний номер',
controller:
controller.contactNumberController),
verticalSpaceSmall,
Container(
padding: EdgeInsets.symmetric(horizontal: 40),
child: CustomTextField(
onSubmit: () => controller
.descripotionFocusNode
.unfocus(),
focusNode: controller.descripotionFocusNode,
maxLenght: 400,
validate: (text) =>
controller.validateTextField(text),
maxline: 10,
minLine: 5,
height: 120.h,
width: 0.8.sw,
controller: controller.descriptionController,
color: AppColors.primaryColorShade,
//description
lableText: 'опис',
),
),
],
),
),
),
I'm making a login form in Flutter, I'm using a ListView that has a Container as a child and it's child is a Stack widget which has Positioned children. Because of the Stack, I have to have a bound height, so hence the Container widget, which I gave the height: height: MediaQuery.of(context).size.height * 1.2. If I remove the * 1.2 my Button and and Text widget don't show up, and when I click on the login with * 1.2, my validator pops up, red warning signs shows that your info is entered incorrectly, so I can't see the button anymore. Example in pictures:
This is with height: MediaQuery.of(context).size.height * 1.2
Then I try to login, validator pops, and now I can't see the button nor the text and link below the button:
The problem I am facing is, how do I layout this login form that can only be scrollable as far as it needs, so I don't have empty space after the Button, just to spread the form so it is visible, not get something like this if I increment the height of the Container?
Code:
ListView(
shrinkWrap: true,
children: [
Container(
height: MediaQuery.of(context).size.height * 1.6,
child: Stack(
children: [
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.1,
child: Image.asset(
'assests/images/loginform.png',
scale: 2.5,
height: 60,
width: 119,
),
),
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.35,
child: Padding(
padding: const EdgeInsets.only(left: 24.0, right: 25.0),
child: Column(
children: <Widget>[
Form(
key: _registrationFormKey,
child: Column(
children: [
TextFormField(
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().name = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Full name'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your full name';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.phone,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().phoneNumber = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Phone number'),
validator: _validateMobile,
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.streetAddress,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().address = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Address'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your address';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().companyName = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Company name'),
validator: (thisValue) {
if (thisValue.isEmpty) {
return 'Please enter your company name';
}
return null;
},
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().website = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Website name'),
validator: _validateWebsite),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().email = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'E-mail address'),
validator: _validateEmail,
),
SizedBox(
height: 24.0,
),
TextFormField(
keyboardType: TextInputType.text,
obscureText: _obscureText,
textAlign: TextAlign.start,
onChanged: (value) {
context.read<User>().password = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Password',
suffixIcon: IconButton(
icon: const Icon(Icons.visibility_outlined),
onPressed: _togglePassVisibility,
),
),
validator: _validatePassword,
),
],
),
),
FormField<bool>(
// 1
initialValue: _agree,
builder: (FormFieldState<bool> state) {
// 2
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Checkbox(
// 3
value: state.value,
onChanged: (bool val) => setState(() {
// 4
_agree = val;
// 5
state.didChange(val);
}),
),
const Text('I agree with'),
TextButton(
onPressed: () {},
child: Text('Terms and conditions'),
),
],
),
// 6
state.errorText == null
? Text("")
: Text(state.errorText,
style: TextStyle(color: Colors.red)),
],
);
},
// 7
validator: (val) => _validateTerms(_agree),
),
AlarmButtons(
buttonColour: Color(0xFF29ABE2),
buttonText: 'CREATE ACCOUNT',
buttonTextColour: Colors.white,
buttonBorderSide: Colors.white,
onButtonPress: () async {
if (_registrationFormKey.currentState.validate()) {
signUpToCognito(context);
Navigator.pushNamed(
context, ConfirmRegistrationScreen.id);
}
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Already have an account?'),
TextButton(
onPressed: () {
Navigator.pushNamed(context, LoginScreen.id);
},
child: Text('Log in'),
),
],
),
],
),
),
),
],
),
)
],
)
Thanks in advance for the help and suggestions!
there are a couple mistakes (or at least optimizations) in your code. I will go over them one by one:
If you have a small number of children that need to be scrolled, it is better to use a SingleChildScrollView with a Column instead of a list view. ListView builds its children lazily - that is, it only builds widgets that are visible on the screen. If you have only a handful of widgets with no complex animations, then you don't really need that. SingleChildScrollView is more flexible that a ListView.
SingleChildScrollView(
child: Column(
children: [...]
)
)
It seems that you want the image to be on the background with the form validation on top of it. For that, you used a Stack and a Column as children to a ListView. Instead, have the Stack as a parent, with both the ListView and the image as children to the Stack. Now this might produce an error, as the ListView might expand infinitely. A simple solution is to wrap it within a Positioned widget with all its sides set to zero.
Stack(
children: [
BackgroundImageWidget(),
Positioned(
top: 0, bottom: 0, left: 0, right: 0, // or width: screenWidth, height: screenHeight,
child: ListView(...),
)
]
)
I'm trying to clear the text when a user click on the X icon and my search result got empty when I click it but my input text is still there so I would be really appreciated if I can get any help or suggestion on how I can clear the inputed text too.
Expanded(
flex: 8,
child: GestureDetector(
onTap: () {},
child: TextFormField(
autofocus: true,
enabled: true,
onChanged: (va) {
filterSearchResult(va, model);
},
decoration: InputDecoration(
floatingLabelBehavior:
FloatingLabelBehavior.never,
border: InputBorder.none,
hintStyle: TextStyle(
color:
Theme.of(context).secondaryHeaderColor)),
),
)),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
items.clear();
itemList.clear();
});
},
child: Image.asset(
"assets/icons/cancel.png",
color: Theme.of(context).secondaryHeaderColor,
height: 30,
)),
),
You should use TextEditingController to clear the value of TextFormField.
// Some code ...
final textEditingController = TextEditingController();
// Some code ...
Expanded(
flex: 8,
child: GestureDetector(
onTap: () {},
child: TextFormField(
autofocus: true,
enabled: true,
controller: textEditingController, // Your TextEditingController here
onChanged: (va) {
filterSearchResult(va, model);
},
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
hintStyle:
TextStyle(color: Theme.of(context).secondaryHeaderColor),
),
),
),
),
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
textEditingController.clear(); // Clear the TextFormField
items.clear();
itemList.clear();
});
},
child: Image.asset(
"assets/icons/cancel.png",
color: Theme.of(context).secondaryHeaderColor,
height: 30,
),
),
),
I use TextEditingController myController and set myController.text to null
Hello Flutter Expert,
Thank you very much for your help in learning Flutter & Dart. Now I got into another problem and need help.
I'm creating a list of widgets with a delete icon so I can remove items if required. When I click on remove, the last item gets removed irrespective of position. Seems like the index is updated insider onPressed() event. I'm not sure how can I fix it. can you pls check below and help me fix it? Thanks
List<ParcelItem> parcelItems = List<ParcelItem>();
void addParcelItem(ParcelItem pi) {
parcelItems.add(pi);
}
void removeParcelItem(index){
parcelItems.removeAt(index);
}
Widget getItemList() {
List<Widget> widgetItems = List<Widget>();
int index = 0;
for (ParcelItem itm in parcelItems) {
itm.id = index;
Widget widgetItem =
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
flex: 40,
child: TextFormField(
initialValue: itm.name,
//keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: 'Name '),
onSaved: (value) {
//print(value);
name = value;
}
),
),
Flexible(
flex: 25,
child: TextFormField(
initialValue: itm.description,
//keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: 'Description '),
onSaved: (value) {
//print(value);
description = value;
}
),
),
Flexible(
flex: 5,
child: TextFormField(
initialValue: itm.quantity.toString(),
keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: 'Quantity '),
onSaved: (value) {
//print(value);
quantity = int.parse(value);
}
),
),
Flexible(
flex: 20,
child: TextFormField(
initialValue: itm.price.toString(),
keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: 'Price '),
onSaved: (value) {
//print(value);
price = double.parse(value);
}
),
),
Flexible(
flex: 10,
child: Center(
child: IconButton(
onPressed: (){
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Warning'),
content: Text('Are you sure you want to delete this record?'),
actions: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: (){
parcelItems.removeWhere((itm){ return (itm.id == parcelItems[index].id); });
},
),
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
},
icon: Icon(Icons.close),
),
),
),
],
);
widgetItems.add(widgetItem);
index++;
}
if (widgetItems != null) {
return Column(
children: widgetItems,
);
} else {
return Text('Add some items', style: kInstructionText,);
}
}
Try this,
List<ParcelItem> parcelItems = List<ParcelItem>();
void addParcelItem(ParcelItem pi) {
parcelItems.add(pi);
}
void removeParcelItem(index) {
parcelItems.removeAt(index);
}
Widget getItemList() {
List<Widget> widgetItems = List<Widget>();
int index = 0;
for (ParcelItem itm in parcelItems) {
itm.id = index;
Widget widgetItem = Row(
key: ObjectKey(itm), //TODO: Added Key Here
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
flex: 40,
child: TextFormField(
initialValue: itm.name,
//keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Name '),
onSaved: (value) {
//print(value);
name = value;
}),
),
Flexible(
flex: 25,
child: TextFormField(
initialValue: itm.description,
//keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Description '),
onSaved: (value) {
//print(value);
description = value;
}),
),
Flexible(
flex: 5,
child: TextFormField(
initialValue: itm.quantity.toString(),
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Quantity '),
onSaved: (value) {
//print(value);
quantity = int.parse(value);
}),
),
Flexible(
flex: 20,
child: TextFormField(
initialValue: itm.price.toString(),
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Price '),
onSaved: (value) {
//print(value);
price = double.parse(value);
}),
),
Flexible(
flex: 10,
child: Center(
child: IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Warning'),
content:
Text('Are you sure you want to delete this record?'),
actions: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: () {
setState((){ //TODO: I assume this `getItemList` function is inside an State class
parcelItems.remove(itm); //TODO: doing this is will do the trick
});
},
),
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
icon: Icon(Icons.close),
),
),
),
],
);
widgetItems.add(widgetItem);
index++;
}
if (widgetItems != null) {
return Column(
children: widgetItems,
);
} else {
return Text(
'Add some items',
style: kInstructionText,
);
}
}