How do you stop a Flutter "Form" from throwing errors? - forms

Working on my personal site, and I want to add a contact form so anyone on the site can fill out a simple form and the site will send me an email. I think I've figured out the email part, but the form the users would have to fill out isn't working yet.
Whenever I start debugging my code it loads into my home page. I click on "Contact Me" at the top right and it takes me to the form page just like it's supposed to, but it immediately shows
Below is my contact_form.dart file in its entirety:
import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../extensions/email_detection_extension.dart';
import '../../extensions/hover_extensions.dart';
class ContactForm extends StatefulWidget {
const ContactForm({Key key}) : super(key: key);
#override
_ContactFormState createState() => _ContactFormState();
}
class _ContactFormState extends State<ContactForm> {
static const bool _autovalidate = false;
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _messageController = TextEditingController();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
autovalidate: _autovalidate, //as you can see I have autovalidate disabled so that shouldn't be it
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Text(
'Name: ',
style: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
),
SizedBox(width: 10),
SizedBox(
child: TextFormField(
validator: (value){
if(value.isEmpty) return 'This field is required.';
return null;
},
decoration: InputDecoration(
hintText: 'First Last',
hintStyle: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
enabledBorder: const UnderlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
focusedBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
fillColor: Color.fromARGB(255, 255, 255, 255),
focusColor: Color.fromARGB(50, 150, 50, 200),
errorText: 'This field is required.'
),
controller: _nameController
),
width: 500
)
]
),
Row(
children: <Widget>[
Text(
'Email: ',
style: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
),
SizedBox(width: 10),
SizedBox(
child: TextFormField(
validator: (value){
if(!value.isValidEmail()) return 'This field is required and must be of the form "example#website.abc".';
return null;
},
decoration: InputDecoration(
hintText: 'example#website.abc',
hintStyle: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
enabledBorder: const UnderlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
focusedBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
fillColor: Color.fromARGB(255, 255, 255, 255),
focusColor: Color.fromARGB(50, 150, 50, 200),
errorText: 'This field is required and must be of the form "example#website.abc".'
),
controller: _emailController,
keyboardType: TextInputType.emailAddress,
),
width: 500
)
]
),
Row(
children: <Widget>[
Text(
'Message:',
style: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
),
SizedBox(width: 10),
SizedBox(
child: TextFormField(
validator: (value){
if(!value.isValidEmail()) return 'This field is required.';
return null;
},
decoration: InputDecoration(
hintText: 'Message',
hintStyle: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.7,
color: Colors.white,
),
enabledBorder: const UnderlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
focusedBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 220, 220, 220))
),
fillColor: Color.fromARGB(255, 255, 255, 255),
focusColor: Color.fromARGB(50, 150, 50, 200),
errorText: 'This field is required.',
),
controller: _messageController
),
width: 500
)
]
),
//Submit button
GestureDetector(
onTap: () async {
if(_formKey.currentState.validate()){
final Email email = Email(
subject: 'Contact Email from ' + _nameController.text,
body: 'Dear Future Me,\n\n' + _nameController.text + " sent you an email from your contact form just now. Here's their message:\n\n" + _messageController.text + '\n\nYou can reach out to them at their provided email: ' + _emailController.text + '\n\nHave a good one, and keep that chin up!\n ~Pseudo-Robotic Past You',
recipients: ['redacted (my email address)'],
isHTML: false
);
try {
await FlutterEmailSender.send(email);
//Navigate to success page
} catch (error) {
//Navigate to failure page
}
}
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 60, vertical: 15),
child: Text(
'Submit',
style: GoogleFonts.ubuntu(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
decoration: BoxDecoration(
color: Color.fromARGB(255, 120, 20, 220),
borderRadius: BorderRadius.circular(5)
),
width: 200
),
).showCursorOnHover
]
)
);
}
}
It's not perfect, I'm gonna clean it up when I'm done, but this is where I stand. Been at this for about 2.5 hours, it's 2 am, and I have a partially functional form that doesn't want to stop erroring. (It shows the error messages even after I've put in acceptable strings and hit submit.) I'd appreciate any ideas on how to fix my autovalidation problem.
Thanks.

Related

Exception caught by widgets library - Null check operator used on a null value

On the sign-up page when the user enters the email that was used before, this exception happens (Null check operator used on a null value)
[firebase_auth/email-already-in-use] The email address is already in use by another account.
════════ Exception caught by widgets library ═══════════════════════════════════
The following _CastError was thrown building Builder(dirty):
Null check operator used on a null value
this is my code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:toto/main.dart';
import 'home.dart';
class CreateAccount extends StatefulWidget {
#override
_CreateAccountState createState() => _CreateAccountState();
}
class _CreateAccountState extends State<CreateAccount> {
//FirebaseAuth fireauth = FirebaseAuth.instance;
//FirebaseFirestore firestore = FirebaseFirestore.instance;
final _auth = FirebaseAuth.instance;
final _Key = GlobalKey<FormState>();
final emailController = TextEditingController();
final passwordController = TextEditingController();
final ageController = TextEditingController();
final usernameController = TextEditingController();
final nameController = TextEditingController();
final numericRegex = RegExp(r'[0-9]');
final CharRegex = RegExp(r'[!##\$&*~]');
final LetterRegex = RegExp(r'[a-z A-Z]');
bool isVisible = false;
var errorMessage = '';
//--------------------------------------validations-----------------------
String? validateName(String? formName) {
final nameRegex = RegExp(
r'^[\u0600-\u065F\u066A-\u06EF\u06FA-\u06FFa-zA-Z]+[\u0600-\u065F\u066A-\u06EF\u06FA-\u06FFa-zA-Z-_]{1,20}$');
if (formName == null || formName.isEmpty)
return 'الاسم مطلوب';
else if (!nameRegex.hasMatch(formName))
return 'يجب أن يتكون الأسم من حروف فقط';
else
return null;
}
String? validateEmail(String? formEmail) {
if (formEmail == null || formEmail.isEmpty)
return 'البريد الالكتروني مطلوب';
String pattern = r'\w+#\w+\.\w+';
RegExp regex = RegExp(pattern);
if (!regex.hasMatch(formEmail))
return 'صيغة البريد الالكتروني غير صحيحة';
else
return null;
}
String? validatePassword(String? formPassword) {
if (formPassword == null || formPassword.isEmpty)
return 'كلمة المرور مطلوبة';
else if (formPassword.length < 8)
return 'يجب ان تحتوي كلمة السر على 8 خانات أو أكثر';
else if (!numericRegex.hasMatch(formPassword) &&
!LetterRegex.hasMatch(formPassword))
return 'يجب أن تحتوي كلمة المرور على أرقام وحروف';
else
return null;
}
bool obscure_text = true;
Icon iconfirst = Icon(
Icons.visibility_off,
color: Color.fromARGB(255, 255, 255, 255),
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:
//SafeArea(
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 35.0),
//padding: const EdgeInsets.fromLTRB(0, 70, 0, 0),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/housebg.png'),
fit: BoxFit.cover),
),
child: Center(
child: SingleChildScrollView(
child: Form(
key: _Key,
child: Column(
children: [
SizedBox(
height: 90,
),
Text(
"تسجيل حساب جديد",
style: TextStyle(
fontSize: 33.0,
color: Color.fromARGB(255, 29, 22, 13),
fontWeight: FontWeight.bold,
fontFamily: "ElMessiri"),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
),
//------------------------------name---------------------------------------
SizedBox(
height: 20.0,
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 0, 30, 0),
child: Text(
"الاسم",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 34, 75, 12),
fontWeight: FontWeight.bold,
),
),
),
TextFormField(
controller: nameController,
validator: validateName,
textAlign: TextAlign.right,
cursorColor: Color(0xFF90B28D),
decoration: InputDecoration(
fillColor: Colors.white,
counterText: "",
filled: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
suffixIcon: Icon(
Icons.person,
color: Color(0xFF90B28D),
),
hintText: "الاسم",
hintStyle: TextStyle(
color: Color(0xFF909A99),
),
),
),
//------------------------age---------------------
SizedBox(
height: 10.0,
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 0, 30, 0),
child: Text(
"العمر",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 34, 75, 12),
fontWeight: FontWeight.bold,
),
),
),
TextFormField(
controller: ageController,
textAlign: TextAlign.right,
cursorColor: Color(0xFF90B28D),
decoration: InputDecoration(
fillColor: Colors.white,
counterText: "",
filled: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
suffixIcon: Icon(
Icons.calendar_month,
color: Color(0xFF90B28D),
),
hintText: "العمر",
hintStyle: TextStyle(
color: Color(0xFF909A99),
),
),
keyboardType: TextInputType.number,
),
//------------------------Username-----------------------------
SizedBox(
height: 10.0,
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 0, 30, 0),
child: Text(
"اسم المستخدم",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 34, 75, 12),
fontWeight: FontWeight.bold,
),
),
),
TextFormField(
controller: usernameController,
validator: (value) {
////////// validator /////////////
if (value!.isEmpty) {
return 'يجب ادخال اسم المستخدم';
} else if (value.contains('0')) {
// اشيك في الداتابيس
return 'اسم المستخدم محجوز';
} else
return null;
},
textAlign: TextAlign.right,
decoration: InputDecoration(
fillColor: Colors.white.withOpacity(0.9),
filled: true,
counterText: "",
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
suffixIcon: Icon(
Icons.account_box,
color: Color(0xFF90B28D),
),
hintText: "اسم المستخدم",
hintStyle: TextStyle(
color: Color(0xFF909A99),
),
),
),
//-----------------------------email----------------------------------
SizedBox(
height: 10.0,
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 0, 30, 0),
child: Text(
"البريد الإلكتروني",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 34, 75, 12),
fontWeight: FontWeight.bold,
),
),
),
TextFormField(
controller: emailController,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: validateEmail,
textAlign: TextAlign.right,
cursorColor: Color(0xFF90B28D),
decoration: InputDecoration(
fillColor: Colors.white.withOpacity(0.9),
counterText: "",
filled: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
suffixIcon: Icon(
Icons.mail,
color: Color(0xFF90B28D),
),
hintText: 'email#address.com',
hintStyle: TextStyle(
color: Color(0xFF909A99),
),
),
keyboardType: TextInputType.emailAddress,
),
//-------------------------------password-----------------------------
SizedBox(
height: 10.0,
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 0, 30, 0),
child: Text(
"كلمة المرور",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 34, 75, 12),
fontWeight: FontWeight.bold,
),
),
),
TextFormField(
controller: passwordController,
validator: validatePassword,
textAlign: TextAlign.right,
obscureText: obscure_text,
decoration: InputDecoration(
fillColor: Colors.white.withOpacity(0.9),
counterText: "",
filled: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(30)),
suffixIcon: Icon(
Icons.lock,
color: Color(0xFF90B28D),
),
prefixIcon: GestureDetector(
onTap: () {
setState(() {
if (obscure_text == true) {
obscure_text = false;
iconfirst = Icon(
Icons.visibility,
color: Color(0xFF90B28D),
);
} else {
obscure_text = true;
iconfirst = Icon(
Icons.visibility_off,
color: Colors.grey.shade300,
);
}
});
},
child: iconfirst,
),
hintText: "كلمة المرور",
hintStyle: TextStyle(
color: Color(0xFF909A99),
),
),
),
SizedBox(
height: 20.0,
),
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
),
ElevatedButton(
onPressed: () async {
register(emailController.text.trim(),
passwordController.text);
},
style: ElevatedButton.styleFrom(
fixedSize: Size(280, 40),
backgroundColor: Color(0xFFA03C1B),
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(30),
),
)),
child: Text(
"تسجيل ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "ElMessiri",
fontSize: 22.0,
color: Colors.white),
textAlign: TextAlign.center,
),
),
//////////////////////////////////////// have an account
Container(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: main,
style: ButtonStyle(
alignment: Alignment.center,
),
child: Text(
"تسجيل دخول",
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 0, 0, 0)),
),
),
Text(
"لديك حساب؟",
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "ElMessiri",
fontSize: 16.0,
color: Color.fromARGB(255, 0, 0, 0)),
),
],
),
),
),
],
),
),
),
),
),
),
);
}
void register(String email, String password) async {
if (_Key.currentState!.validate()) {
try {
await _auth
.createUserWithEmailAndPassword(email: email, password: password)
.then((value) => {postDetailsToFirestore()});
} on FirebaseAuthException catch (error) {
print(error);
errorMessage = error.message!;
Map<String, String?> codeResponses = {
// Re-auth responses
"user-mismatch": 'المستخدم غير متطابق',
"user-not-found": 'لم يتم العثور على المستخدم',
"invalid-credential": 'invalid credential',
"invalid-email": 'الايميل غير موجود',
"wrong-password": 'كلمة المرور الحالية خاطئة',
"invalid-verification-code": 'رمز التحقق غير صالح',
"invalid-verification-id": 'معرّف التحقق غير صالح',
"user-disabled": 'المستخدم لهذا الايميل معطّل',
"too-many-requests": 'طلبات كثيرة',
"operation-not-allowed":
'تسجيل الدخول من خلال الايميل وكلمة المرور غير مسموح',
// Update password error codes
"weak-password": 'كلمة المرور غير قوية',
"requires-recent-login": 'يتطلب تسجيل دخول حديث'
};
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(codeResponses[error.code]!),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, 'حسنًا'),
child: const Text('حسنًا'),
)
]);
});
}
}
}
postDetailsToFirestore() async {
User? user = _auth.currentUser;
try {
await FirebaseFirestore.instance.collection("users").doc(user?.uid).set({
'userID': user?.uid,
'name': nameController.text,
'age': ageController.text,
'username': usernameController.text,
'email': emailController.text,
});
print(nameController.text);
print(ageController.text);
print(usernameController.text);
print(emailController.text);
//if(ageController.text>='60'){
Navigator.pushAndRemoveUntil((context),
MaterialPageRoute(builder: (context) => home()), (route) => false);
} on FirebaseAuthException catch (error) {
errorMessage = error.message!;
}
}
}
Two ways to fix this,
Make the below change
showDialog(
context: context,
builder: (context) {
return AlertDialog(
// add -> ?? "Unknown Error" to below line
content: Text(codeResponses[error.code] ?? "Unknown error"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, 'حسنًا'),
child: const Text('حسنًا'),
)
]);
});
Or
Add email-already-in-use to codeResponses
Map<String, String?> codeResponses = {
// Re-auth responses
"user-mismatch": 'المستخدم غير متطابق',
"user-not-found": 'لم يتم العثور على المستخدم',
"email-already-in-use" : 'Email already in use',

mutation graphql using flutter forms not working

trying to use mutation on forms but got this error while addins runmutation and queryresult result in builder ().all i get is dead code in vscode
The argument type 'Widget Function(MultiSourceResult Function(Map<String, dynamic>, {Object? optimisticResult}), QueryResult<Object?>)' can't be assigned to the parameter type 'Widget Function(MultiSourceResult<Object?> Function(Map<String, dynamic>, {Object? optimisticResult}), QueryResult
import 'dart:io';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:project/API/Api.dart';
import 'package:project/screens/form_info.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import '../API/querys.dart';
import '../API/mutations.dart';
class Sign_Number extends StatefulWidget {
Sign_Number({Key? key}) : super(key: key);
#override
State<Sign_Number> createState() => _Sign_NumberState();
}
class _Sign_NumberState extends State<Sign_Number> {
var PhoneNumber = "";
void _onCountryChange(CountryCode countryCode) {
this.PhoneNumber = countryCode.toString();
print("new country selected: " + countryCode.toString());
}
TextEditingController phoneNumberhere = TextEditingController();
TextEditingController password = TextEditingController();
void initState() {
super.initState();
_onCountryChange(CountryCode());
this.PhoneNumber = "+20";
}
var _formKey1 = new GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return GraphQLProvider(
client: client,
child: MaterialApp(
home: Container(
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.5, 0.5],
colors: <Color>[Color.fromRGBO(0, 37, 43, 1), Colors.white],
tileMode:
TileMode.clamp, // clamp the gradient over the canvas
),
),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Container(Image(
// height: MediaQuery.of(context).size.height *0.5,
// width: 250,
// image: AssetImage('assets/images/2.jpg')),
// ),
Container(
height: 300,
width: 300,
child: const Image(
image: AssetImage(
'assets/images/2.jpg',
),
fit: BoxFit.cover,
),
),
const SizedBox(
//Use of SizedBox
height: 30,
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
child: Row(
children: [
const SizedBox(
width: 47,
),
const Text("Enter mobile number for login",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold)),
],
)),
const SizedBox(
//Use of SizedBox
height: 20,
),
Mutation(
options: new MutationOptions(
document: gql(insertUser()),
/// Tell the GraphQL client to fetch the data from
/// the network only and don't cache it
fetchPolicy: FetchPolicy.noCache,
/// Whenever the [Form] closes, this tells the previous [route]
/// whether it needs to rebuild itself or not
onCompleted: (data) =>
Navigator.pop(context, data != null),
),
builder: (QueryResult, RunMutation) {
return Form(
key: _formKey1,
child: Container(
height: 100,
padding: const EdgeInsets.symmetric(
horizontal: 30),
child: Column(children: [
TextFormField(
controller: phoneNumberhere,
autocorrect: true,
keyboardType:
TextInputType.number,
onFieldSubmitted: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Enter a valid Phone Number!';
}
return null;
},
decoration: InputDecoration(
prefixIcon: CountryCodePicker(
onChanged: _onCountryChange,
// Initial selection and favorite can be one of code ('IT') OR dial_code('+39')
initialSelection: '+20',
favorite: ['+20', 'EG'],
textStyle: const TextStyle(
color: Colors.black),
showFlag: true,
),
contentPadding:
const EdgeInsets.all(10),
hintText:
'Enter valid phone number...',
hintStyle: const TextStyle(
color: Colors.black),
filled: true,
fillColor: const Color.fromRGBO(
227, 227, 226, 0.2),
enabledBorder:
const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
12.0)),
borderSide: BorderSide(
color: Colors.white,
width: 2),
),
focusedBorder:
const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
10.0)),
borderSide: BorderSide(
color: Colors.white),
),
),
),
const SizedBox(
//Use of SizedBox
height: 10,
),
SizedBox(
height: 50,
child: TextFormField(
autofocus: false,
obscureText: true,
controller: password,
autocorrect: true,
keyboardType: TextInputType
.visiblePassword,
onFieldSubmitted: (value) {},
validator: (value) {
if (value!.isEmpty) {
return 'Enter a valid password!';
}
return null;
},
decoration: InputDecoration(
contentPadding:
const EdgeInsets.all(10),
hintText: 'Enter Password.',
hintStyle: const TextStyle(
color: Colors.black),
filled: true,
fillColor:
const Color.fromRGBO(
227, 227, 226, 0.2),
enabledBorder:
const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
12.0)),
borderSide: BorderSide(
color: Colors.white,
width: 2),
),
focusedBorder:
const OutlineInputBorder(
borderRadius:
BorderRadius.all(
Radius.circular(
10.0)),
borderSide: BorderSide(
color: Colors.white),
),
),
),
),
const SizedBox(
//Use of SizedBox
height: 5,
),
const Text(
"forgot your password?",
style: TextStyle(
color: Color.fromRGBO(
218, 218, 218, 1),
fontSize: 10),
textAlign: TextAlign.left,
),
])));
const SizedBox(
//Use of SizedBox
height: 50,
);
FlatButton(
height: 50,
minWidth: 300,
onPressed: () {
if (_formKey1.currentState!.validate()) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
MyCustomForm()));
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content:
Text(phoneNumberhere.text)),
);
}
},
color: const Color.fromRGBO(0, 168, 165, 1),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10)),
child: const Text(
"Continue",
style: TextStyle(
color: Colors.white, fontSize: 19),
),
);
},
),
],
)
])))));
}
}```

How to make TextField's label wont move when out of focus in Flutter

I'm new to flutter.
I'm trying to replicate the following UI, it has multiple TextField and all of their labels won't maximize when I click on other TextField, they keep on focus to show the content inside it: https://i.stack.imgur.com/8lUeV.png
The UI I made: https://i.stack.imgur.com/o9Rpj.png
I tried the autofocus: on but it didn't work cuz it only work for one TextField at a time.
My code:
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:login_sample/models/user.dart';
class EmployeeProfile extends StatefulWidget {
const EmployeeProfile({Key? key, required this.user}) : super(key: key);
final User user;
#override
_EmployeeProfileState createState() => _EmployeeProfileState();
}
class _EmployeeProfileState extends State<EmployeeProfile> {
late String name = '';
late String email = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.bottomCenter,
colors: [Colors.blue, Colors.blue])),
height: MediaQuery.of(context).size.height * 0.3
),
Card(
elevation: 20.0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50),
),
),
margin: const EdgeInsets.only(left: 0.0, right: 0.0, top: 100.0),
child: ListView(
children: <Widget>[
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val){
name = val;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Name',
hintText: widget.user.name,
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 107, 106, 144), width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val){
email = val;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Email',
hintText: widget.user.email,
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 107, 106, 144), width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
TextButton(
onPressed: (){
print(widget.user.name);
print(widget.user.email);
setState(() {
widget.user.name = name;
widget.user.email = email;
});
},
child: const Text('Save'),
),
],
)
),
Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(// Add AppBar here only
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
widget.user.name.toString(),
style: const TextStyle(
letterSpacing: 0.0,
fontSize: 20.0,
),
),
),
),
],
),
);
}
}
P/s: sr im not really good at English to describe it correctly
Label will be visible if you focus on the TextField or TextField has content. If what you mean is keeping the label always be visible, you can add floatingLabelBehavior: FloatingLabelBehavior.always on InputDecoration.
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:login_sample/models/user.dart';
class EmployeeProfile extends StatefulWidget {
const EmployeeProfile({Key? key, required this.user}) : super(key: key);
final User user;
#override
_EmployeeProfileState createState() => _EmployeeProfileState();
}
class _EmployeeProfileState extends State<EmployeeProfile> {
late String name = '';
late String email = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.bottomCenter,
colors: [Colors.blue, Colors.blue])),
height: MediaQuery.of(context).size.height * 0.3
),
Card(
elevation: 20.0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50),
),
),
margin: const EdgeInsets.only(left: 0.0, right: 0.0, top: 100.0),
child: ListView(
children: <Widget>[
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val){
name = val;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Name',
hintText: widget.user.name,
// add here
floatingLabelBehavior: FloatingLabelBehavior.always
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 107, 106, 144), width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val){
email = val;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Email',
hintText: widget.user.email,
// add here
floatingLabelBehavior: FloatingLabelBehavior.always
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(color: Color.fromARGB(255, 107, 106, 144), width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
TextButton(
onPressed: (){
print(widget.user.name);
print(widget.user.email);
setState(() {
widget.user.name = name;
widget.user.email = email;
});
},
child: const Text('Save'),
),
],
)
),
Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(// Add AppBar here only
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
widget.user.name.toString(),
style: const TextStyle(
letterSpacing: 0.0,
fontSize: 20.0,
),
),
),
),
],
),
);
}
}
Try below code hope its helpful to you. add your ListView() inside Padding
Padding(
padding: EdgeInsets.all(20),
child: ListView(
children: <Widget>[
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val) {},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Name',
hintText: 'widget.user.name',
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 107, 106, 144),
width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
SizedBox(
height: 20,
),
SizedBox(
child: TextField(
autofocus: true,
onChanged: (val) {},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
labelText: 'Employee Email',
hintText: 'widget.user.email',
labelStyle: const TextStyle(
color: Color.fromARGB(255, 107, 106, 144),
fontSize: 14,
fontWeight: FontWeight.w500,
),
border: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 107, 106, 144),
width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
width: 150.0,
),
TextButton(
onPressed: () {},
child: const Text('Save'),
),
],
),
),
Your Screen->

Make a TextFormField global widget in flutter

I am making a global TextFormField widget for the App. But it is not returning data in the controller.
My Global text form field Widget: Kindly tell me what I am doing wrong. I am initializing the controller in the SignUp person widget. I also want to validate the text form field in the validator.
import 'package:flutter/material.dart';
class GlobalTextField extends StatelessWidget {
final Widget fieldIcon;
final String fieldText;
final TextEditingController fieldController;
final bool isEnabled;
const GlobalTextField(
this.fieldIcon,
this.fieldText,
this.fieldController, [
this.isEnabled,
]);
#override
Widget build(BuildContext context) {
return TextFormField(
controller: fieldController,
enabled: isEnabled ?? true,
decoration: InputDecoration(
hintText: fieldText,
prefixIcon: fieldIcon,
hintStyle: TextStyle(color: Colors.grey),
filled: true,
fillColor: Colors.white70,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(198, 57, 93, 1)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(198, 57, 93, 1)),
),
),
cursorColor: Color.fromRGBO(198, 57, 93, 1),
);
}
}
I used it like
import 'package:flutter/material.dart';
import 'package:neighbourhood_watch/ui/widgets/button_global.dart';
import 'package:neighbourhood_watch/ui/widgets/textfield_global.dart';
import 'package:neighbourhood_watch/widgets/user_image_picker.dart';
import 'dart:io';
class SignUpPerson extends StatefulWidget {
#override
_SignUpPersonState createState() => _SignUpPersonState();
}
class _SignUpPersonState extends State<SignUpPerson> {
TextEditingController username = new TextEditingController();
TextEditingController description = new TextEditingController();
TextEditingController contact = new TextEditingController();
TextEditingController password = new TextEditingController();
TextEditingController area = new TextEditingController();
TextEditingController email = new TextEditingController();
final _formKey = GlobalKey<FormState>();
File _userImageFile;
void _pickedImage(File image) {
_userImageFile = image;
}
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Container(
height: height,
width: width,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: height * 0.05,
width: width,
),
Container(
height: height * 0.25,
width: width,
child: Image.asset(
'assets/images/nhwlogo_global.png',
fit: BoxFit.contain,
),
),
Text(
'Create an Account',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 30.0,
),
Container(
height: height * 0.12,
width: width * 0.5,
child: UserImagePicker(
imagePickFn: _pickedImage,
),
),
SizedBox(
height: 10.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.person,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Username',
username),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.edit,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Description',
description),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.call,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Contact No.',
contact),
),
SizedBox(
height: 15.0,
),
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.cake,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Date of Birth',
password),
),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.location_on,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Area',
area),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.email,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Email',
email),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.lock,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Password',
password),
),
SizedBox(
height: 15.0,
),
Padding(
padding: const EdgeInsets.only(left: 25.0, right: 25.0),
child: GlobalTextField(
Icon(
Icons.lock,
color: Color.fromRGBO(198, 57, 93, 1),
),
'Confirm Password',
password),
),
SizedBox(
height: 70.0,
),
GlobalButton('CONTINUE', () {
print('userName: ${username}');
}, width * 0.7),
SizedBox(
height: 50.0,
),
Text(
'By creating an account you agree to our',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'Terms of Service and Privacy Policy',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(198, 57, 93, 1),
),
),
SizedBox(
height: 50.0,
),
],
),
),
),
),
);
}
}
Please create a static (Global) function like below, and just use it in your regular form widget. You will have the validator function, pass it and it will work:
static Widget MyInputField(
{String initialValue = "",
Function(String) onSaved,
String hint,
bool hide = false,
Icon prefixIcon,
Widget suffixIcon,
bool enabled = true,
TextInputType textInputType = TextInputType.emailAddress,
Function(bool) onSuffixIconClick,
Function(String) validator}) {
return SizedBox(
child: TextFormField(
initialValue: initialValue,
obscureText: hide,
onSaved: onSaved,
enabled: enabled,
decoration: new InputDecoration(
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
fillColor: enabled ? MyColor.white : MyColor.disabledColor,
filled: true,
contentPadding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: MyColor.accentColor, width: 1.0),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 1.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: MyColor.primaryColor, width: 1.0),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.green, width: 1.0),
),
hintText: hint,
),
validator: validator,
keyboardType: textInputType,
style:
MyStyle.titleStyle(enabled ? MyColor.primaryColor : Colors.white),
),
);
}
Please let me know if things go well. Have a good day.
thanks to all the developers. This is because I am using the const GlobalTextWidget constructor, I just remove the const keyword and it is now working fine.
If you want to return data from your TextField then you can try the below code this will help for you.
GlobalButton('CONTINUE', () {
print("Username${username.text.toString()}");
print("Descriptiom${description.text.toString()}");
}, width * 0.7),

Flutter-> TextField hidden by KeyBoard

i have a problem, when i'm focusing on a TextFormField, my keyBoard come over this one. I have tried so much differents ways.
I have found one single solution but my view begin from the bottom to the top and i want the opposite.
I hope someone got a solution to auto scroll the TextFormField, thank you !
My code here :
final _formKey = GlobalKey<FormState>();
#override
void initState() {
super.initState();
}
#override
void dispose() {
nomController.dispose();
adresseController.dispose();
complementAdresseController.dispose();
villeController.dispose();
codePostalController.dispose();
super.dispose();
}
//controller for get value from TextFormField
TextEditingController nomController = TextEditingController();
TextEditingController adresseController = TextEditingController();
TextEditingController complementAdresseController = TextEditingController();
TextEditingController villeController = TextEditingController();
TextEditingController codePostalController = TextEditingController();
//save value in variables for send data from http request
String nom;
String adresse;
String complement;
String ville;
String codePostal;
final ScrollController _scrollController = ScrollController();
sendFormData() async {
var postUri = Uri.parse("http://51.158.67.16:8000/api/contact/");
var request = new http.MultipartRequest("POST", postUri);
request.fields['name'] = nom;
request.fields['adresse'] = adresse;
request.fields['complement'] = complement;
request.fields['city'] = ville;
request.fields['postalCode'] = codePostal;
print(nom);
print(adresse);
print(complement);
print(ville);
print(codePostal);
request.send().then((response) {
if (response.statusCode == 201) {
print("Uploaded!");
} else {
print(response.statusCode);
}
});
}
validateAndSave() async {
final form = _formKey.currentState;
if (form.validate()) {
setState(() {
nom = nomController.text;
adresse = adresseController.text;
complement = complementAdresseController.text;
ville = villeController.text;
codePostal = codePostalController.text;
});
await sendFormData();
} else {
print('form is invalid');
}
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SafeArea(
top: false,
bottom: false,
child: Container(
color: Color.fromRGBO(22, 22, 22, 1.0),
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0),
child: Text(
'Veuillez remplir les champs si dessous afin de nous communiquer l\'emplacement et le nom du monument ou de l\'oeuvre',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontFamily: 'Nunito',
),
),
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Nom de l’oeuvre",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: new TextFormField(
style: TextStyle(color: Colors.white),
controller: nomController,
onChanged: (value) {
setState(() {
nom = value;
});
},
validator: (value) {
if (value.length <= 4) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"Le nom doit contenir au minimum 4 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
],
));
}
return null;
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color:
Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Nom du monument, oeuvre...',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Adresse",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: adresseController,
onChanged: (value) {
setState(() {
adresse = value;
});
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(
Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0),
),
hintText: '( Optionnel ) Adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Complément d'adresse",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: complementAdresseController,
onChanged: (value) {
setState(() {
complement = value;
});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color:
Color.fromRGBO(133, 133, 133, 1.0)),
hintText: '(Optionnel) Complement d’adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Ville",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: villeController,
onChanged: (value) {
setState(() {
ville = value;
});
},
validator: (value) {
if (value.length <= 2) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(
40, 40, 40, 1.0),
titleTextStyle: TextStyle(
color: Colors.white),
title: Text(
"La ville doit contenir au minimum 2 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(
context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors
.white)),
)
]));
}
return null;
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(
133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(
133, 133, 133, 1.0)),
hintText: 'Ville',
fillColor:
Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius:
BorderRadius.circular(10.0),
)),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Code Postal",
style: TextStyle(
color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: codePostalController,
onChanged: (value) {
setState(() {
codePostal = value;
});
},
validator: (value) {
if (value.length != 5) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(
40, 40, 40, 1.0),
titleTextStyle: TextStyle(
color: Colors.white),
title: Text(
"Le code postal doit contenir 5 chiffres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(
context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors
.white)),
)
]));
}
return null;
},
keyboardType: TextInputType.number,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color:
Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
),
suffixIcon: Icon(Icons.search,
color:
Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Code postal',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
),
),
)),
FlatButton(
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
onPressed: () async {
await validateAndSave();
},
textColor: Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 60),
child: Container(
alignment: Alignment(0, 0),
width: MediaQuery.of(context).size.width / 2,
height: 65,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10.0)),
color:
Color.fromRGBO(243, 243, 243, 1.0)),
child: Text(
'ENVOYER',
style: TextStyle(
fontSize: 18,
color: Color.fromRGBO(40, 40, 40, 1.0)),
),
//padding: EdgeInsets.fromLTRB(0, 53, 0, 20),
),
)),
],
))
]))));
}
}```
Your page should contain Scaffold widget to get the auto scroll feature.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: MyPage()), //TODO: Add Scaffold
);
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final _formKey = GlobalKey<FormState>();
#override
void initState() {
super.initState();
}
#override
void dispose() {
nomController.dispose();
adresseController.dispose();
complementAdresseController.dispose();
villeController.dispose();
codePostalController.dispose();
super.dispose();
}
//controller for get value from TextFormField
TextEditingController nomController = TextEditingController();
TextEditingController adresseController = TextEditingController();
TextEditingController complementAdresseController = TextEditingController();
TextEditingController villeController = TextEditingController();
TextEditingController codePostalController = TextEditingController();
//save value in variables for send data from http request
String nom;
String adresse;
String complement;
String ville;
String codePostal;
final ScrollController _scrollController = ScrollController();
sendFormData() async {
var postUri = Uri.parse("http://51.158.67.16:8000/api/contact/");
var request = new http.MultipartRequest("POST", postUri);
request.fields['name'] = nom;
request.fields['adresse'] = adresse;
request.fields['complement'] = complement;
request.fields['city'] = ville;
request.fields['postalCode'] = codePostal;
print(nom);
print(adresse);
print(complement);
print(ville);
print(codePostal);
request.send().then((response) {
if (response.statusCode == 201) {
print("Uploaded!");
} else {
print(response.statusCode);
}
});
}
validateAndSave() async {
final form = _formKey.currentState;
if (form.validate()) {
setState(() {
nom = nomController.text;
adresse = adresseController.text;
complement = complementAdresseController.text;
ville = villeController.text;
codePostal = codePostalController.text;
});
await sendFormData();
} else {
print('form is invalid');
}
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SafeArea(
top: false,
bottom: false,
child: Container(
color: Color.fromRGBO(22, 22, 22, 1.0),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0),
child: Text(
'Veuillez remplir les champs si dessous afin de nous communiquer l\'emplacement et le nom du monument ou de l\'oeuvre',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontFamily: 'Nunito',
),
),
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Nom de l’oeuvre",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: new TextFormField(
style: TextStyle(color: Colors.white),
controller: nomController,
onChanged: (value) {
setState(() {
nom = value;
});
},
validator: (value) {
if (value.length <= 4) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"Le nom doit contenir au minimum 4 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
],
));
}
return null;
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Nom du monument, oeuvre...',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Adresse",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: adresseController,
onChanged: (value) {
setState(() {
adresse = value;
});
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(
Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0),
),
hintText: '( Optionnel ) Adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Complément d'adresse",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: complementAdresseController,
onChanged: (value) {
setState(() {
complement = value;
});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: '(Optionnel) Complement d’adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Ville",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: villeController,
onChanged: (value) {
setState(() {
ville = value;
});
},
validator: (value) {
if (value.length <= 2) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"La ville doit contenir au minimum 2 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
]));
}
return null;
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Ville',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Code Postal",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: codePostalController,
onChanged: (value) {
setState(() {
codePostal = value;
});
},
validator: (value) {
if (value.length != 5) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"Le code postal doit contenir 5 chiffres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
]));
}
return null;
},
keyboardType: TextInputType.number,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Code postal',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
),
),
)),
FlatButton(
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
onPressed: () async {
await validateAndSave();
},
textColor: Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 60),
child: Container(
alignment: Alignment(0, 0),
width: MediaQuery.of(context).size.width / 2,
height: 65,
decoration: const BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0)),
color: Color.fromRGBO(243, 243, 243, 1.0)),
child: Text(
'ENVOYER',
style: TextStyle(
fontSize: 18,
color: Color.fromRGBO(40, 40, 40, 1.0)),
),
//padding: EdgeInsets.fromLTRB(0, 53, 0, 20),
),
),
),
],
),
)
],
),
),
),
);
}
}
I already got a scaffold on my main, i change my widget when icon was clicked on my bottom Navigation bar
my main here:
import 'dart:async';
import 'package:device_id/device_id.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:projet_malvoyant/userScreen.dart';
import 'package:statusbar/statusbar.dart';
import 'downloadScreen.dart';
import 'homePageScreen.dart';
import 'contactScreen.dart';
import 'appBar/contactAppBar.dart';
import 'appBar/downloadAppBar.dart';
import 'device_id.dart';
HomePageScreenState accessLocation;
Timer timer;
void main() async {
runApp(MyApp());
//timer = Timer.periodic(Duration(seconds: 10), (Timer t) => accessLocation.getOeuvreThemeFromLocation());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int _selectedPage = 0;
Color color = Color.fromRGBO(155, 155, 155, 1.0);
#override
Widget build(BuildContext context) {
StatusBar.color(Color.fromRGBO(40, 40, 40, 1.0));
// Device_id.main();
Widget content;
Widget contentAppBar;
switch (_selectedPage) {
case 0:
content = HomePageScreen();
//contentAppBar = HomePageAppBar();
break;
case 1:
content = DownloadScreen();
contentAppBar = DownloadAppBar();
break;
case 2:
content = ContactScreen();
contentAppBar = ContactAppBar();
break;
case 3:
content = UserScreen();
break;
}
return MaterialApp(
title: '',
home: Scaffold(
resizeToAvoidBottomPadding: false,
resizeToAvoidBottomInset: false,
backgroundColor: Color.fromRGBO(22, 22, 22, 1.0),
appBar: contentAppBar,
body: content,
bottomNavigationBar: bottomNavBar(context)));
}
Widget bottomNavBar(BuildContext context) {
return BottomNavigationBar(
currentIndex: _selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
iconSize: 24.0,
showSelectedLabels: false,
showUnselectedLabels: false,
type: BottomNavigationBarType.fixed,
backgroundColor: Color.fromRGBO(40, 40, 40, 1.0),
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(
IconData(
67,
fontFamily: 'Glyphter',
),
color: Colors.white,
size: 27),
title: Text('Accueil'),
),
BottomNavigationBarItem(
icon: Icon(
IconData(
66,
fontFamily: 'Glyphter',
),
color: Colors.white,
size: 27),
title: Text('Téléchargement')),
BottomNavigationBarItem(
icon: Icon(
IconData(
68,
fontFamily: 'Glyphter',
),
color: Colors.white,
size: 27,
),
title: Text(
'',
)),
BottomNavigationBarItem(
icon: Icon(
IconData(
65,
fontFamily: 'Glyphter',
),
color: Colors.white,
size: 27),
title: Text('Courriel')),
],
);
}
}
//Add this line "resizeToAvoidBottomInset: true," to your Scaffold and put your main container in ScrollView.
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
key: _scaffoldKey,
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container()
),
);
}