Flutter - Text forms not moving above the keyboard upon opening - flutter

I am fairly new to flutter and dart as a whole and i have been creating an application that interacts with firebase, this is the code for my registration screen. When clicking on a text input field the keyboard ends up blocking the forms and you cannot see what you are entering... I have tried many things such as singlechildscroll view and resizeToAvoidBottomInset and nothing seems to be affecting it. Anyone have any idea?
Register page:
class RegistrationPage extends StatefulWidget{
const RegistrationPage({Key? key}) : super(key: key);
#override
_RegistrationPageState createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
final _auth = FirebaseAuth.instance;
//our form key
final _formKey = GlobalKey<FormState>();
//editing controllers
final firstNameEditingController = new TextEditingController();
final lastNameEditingController = new TextEditingController();
final emailEditingController = new TextEditingController();
final passwordEditingController = new TextEditingController();
final confirmPasswordEditingController = new TextEditingController();
final cityEditingController = new TextEditingController();
#override
Widget build(BuildContext context) {
//firstname Field
final firstNameField = TextFormField(
autofocus: false,
controller: firstNameEditingController,
keyboardType: TextInputType.name,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("First Name cannot be empty");
}
if(!regEx.hasMatch(value))
{
return("Enter valid name(min 2 characters)");
}
return null;
},
onSaved: (value) {
firstNameEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "First name",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//Last name Field
final lastNameField = TextFormField(
autofocus: false,
controller: lastNameEditingController,
keyboardType: TextInputType.name,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("Last Name cannot be empty");
}
return null;
},
onSaved: (value) {
lastNameEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Last name",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//email Field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.text,
validator: (value)
{
if(value!.isEmpty)
{
return("Please enter your email");
}
//email validation
if(!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]").hasMatch(value))
{
return("Please enter a valid email");
}
},
onSaved: (value) {
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.account_circle),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//City
final cityField = TextFormField(
autofocus: false,
controller: cityEditingController,
keyboardType: TextInputType.text,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{2,}$');
if(value!.isEmpty)
{
return("City cannot be empty");
}
return null;
},
onSaved: (value) {
cityEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.location_on),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "City",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
));
//password Field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value)
{
RegExp regEx = new RegExp(r'^.{6,}$');
if(value!.isEmpty)
{
return("Password is required!");
}
if(!regEx.hasMatch(value))
{
return("Enter valid password(Min. 6 characters)");
}
},
onSaved: (value) {
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
)
);
//Confirm password Field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if (confirmPasswordEditingController.text != passwordEditingController.text){
return "Passwords do not match";
}
return null;
},
onSaved: (value) {
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.done,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Confirm Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
)
)
);
final registerButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.pink,
child: MaterialButton(
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: Text("Register", textAlign:TextAlign.center,
style: TextStyle(
fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
),
)
);
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.pink),
onPressed:(){
Navigator.of(context).pop();
},
)
),
body: Center(
child: new SingleChildScrollView(
reverse: true,
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 180,
child: Image.asset(
"assets/logo.png",
fit: BoxFit.contain,
)),
SizedBox(height: 30),
firstNameField,
SizedBox(height: 10),
lastNameField,
SizedBox(height: 10),
emailField,
SizedBox(height:10),
cityField,
SizedBox(height: 10),
passwordField,
SizedBox(height: 10),
confirmPasswordField,
SizedBox(height: 10),
registerButton,
],
),
),
)
)
)
)
);
Main.dart
Future<void> main() async { //asynchronous programming, waits for events to happen before producing a result
WidgetsFlutterBinding.ensureInitialized(); //in this case initializes the Firebase waits for a callback
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget { //Used to build application
const MyApp({Key? key}) : super(key: key); //Anything in here runs when the app starts
ThemeData _appTheme() { //The login screen is first to load but this is not in place of main as it is bad practise
final ThemeData base = ThemeData.light(); //Will be used for implementation of light and dark theme
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: travelBlue,
onPrimary: Colors.white,
secondary: travelBlue,
error: travelErrorRed,
),
);
}
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp( //Runs when main.dart is executed
title: 'Login',
theme: _appTheme(),
home: LoginPage(),
);
}
}

try wrapping your column with padding
Padding(
padding: MediaQuery.of(context).viewInsets,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// your entire form widgets here
]
)
)

Related

Error when focussing on next Focus in Flutter

If I click away from a TextField and then back on it and want to focus on the next TextField (using FocusScope.of(context).nextFocus()) by hitting enter on the software keyboard I get this error:
Exception has occurred.
_AssertionError ('package:flutter/src/widgets/focus_manager.dart': Failed assertion: line 790 pos 7: 'context != null': Tried to get the bounds of a focus node that didn't have its context set yet.
The context needs to be set before trying to evaluate traversal policies. Setting the context is typically done with the attach method.)
This is my code:
import 'package:quizlet/api/convert_json.dart';
import 'package:quizlet/style.dart';
class CreateQuiz extends StatefulWidget {
const CreateQuiz({super.key});
#override
State<CreateQuiz> createState() => _CreateQuizState();
}
class _CreateQuizState extends State<CreateQuiz> {
int wordCount = 3;
List errorDefinitions = [false, false, false];
List errorAnswers = [false, false, false];
bool errorTitle = false;
bool errorDescription = false;
final List definitions = [
TextEditingController(),
TextEditingController(),
TextEditingController()
];
final List answers = [
TextEditingController(),
TextEditingController(),
TextEditingController()
];
final title = TextEditingController();
final description = TextEditingController();
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
final brightness = MediaQuery.of(context).platformBrightness;
bool darkMode = brightness == Brightness.dark;
final hintColor = darkMode ? Colors.white : Colors.black;
return Scaffold(
appBar: AppBar(
title: const Text("Create Quiz"),
actions: [
TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
),
onPressed: () {
onPressed();
},
child: Text(
"Done",
style: TextStyle(fontSize: height / 55),
),
),
],
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView(
children: [
SizedBox(
height: height / 40,
),
TextField(
onSubmitted: (value) {
FocusScope.of(context).nextFocus();
},
onChanged: (value) {
setState(() {
errorTitle = false;
});
},
textInputAction: TextInputAction.next,
onEditingComplete: () {},
keyboardType: TextInputType.multiline,
controller: title,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
hintStyle: TextStyle(
color: errorTitle ? Colors.red : hintColor,
),
hintText: errorTitle ? "Title can't be blank" : "Title",
border: const OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorTitle ? Colors.red : color1,
width: 2.0,
),
),
),
),
const SizedBox(
height: 5,
),
TextField(
onSubmitted: (value) {
FocusScope.of(context).nextFocus();
},
onChanged: (value) {
setState(() {
errorDescription = false;
});
},
textInputAction: TextInputAction.newline,
onEditingComplete: () {},
controller: description,
maxLines: null,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
hintText: errorDescription
? "Description can't be blank"
: "Description",
hintStyle: TextStyle(
color: errorDescription ? Colors.red : hintColor,
),
border: const OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorDescription ? Colors.red : color1,
width: 2.0,
),
),
),
),
SizedBox(
height: height / 20,
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: wordCount,
itemBuilder: (BuildContext context, int i) {
return Column(
children: [
TextField(
onSubmitted: (value) {
FocusScope.of(context).nextFocus();
},
onChanged: (value) {
setState(() {
errorDefinitions[i] = false;
});
},
textInputAction: TextInputAction.next,
onEditingComplete: () {},
autocorrect: false,
controller: definitions[i],
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
hintStyle: TextStyle(
color: errorDefinitions[i] ? Colors.red : hintColor,
),
hintText: errorDefinitions[i]
? "Definition can't be blank"
: "Definition",
border: const OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorDefinitions[i] ? Colors.red : color1,
width: 2.0,
),
),
),
),
const SizedBox(
height: 5,
),
TextField(
onSubmitted: (value) {
setState(() {
if (definitions[i].text != "" &&
answers[i].text != "") {
if (i + 2 >= wordCount) {
wordCount++;
definitions.add(TextEditingController());
answers.add(TextEditingController());
errorAnswers.add(false);
errorDefinitions.add(false);
}
FocusScope.of(context).nextFocus();
}
});
},
onChanged: (value) {
setState(() {
errorAnswers[i] = false;
});
},
textInputAction: TextInputAction.next,
onEditingComplete: () {},
autocorrect: false,
controller: answers[i],
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(10.0),
hintStyle: TextStyle(
color: errorAnswers[i] ? Colors.red : hintColor,
),
hintText: errorAnswers[i]
? "Answer can't be blank"
: "Answer",
border: const OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: errorAnswers[i] ? Colors.red : color1,
width: 2.0,
),
),
),
),
SizedBox(
height: height / 50,
),
],
);
},
),
],
),
),
),
);
}```

How to update variables of a State class inside of an external Widget?

I'm new in flutter, Can someone help me how to access the ss variable or the setState protected method of a State class I created inside of a Widget outside that class. I'm trying to organize codes that's why I extract the Widget out of that State class.
main.dart
import 'package:flutter/material.dart';
import 'screens.dart';
void main() => runApp(const App());
enum ScreenState {
home,
login,
register,
}
class App extends StatefulWidget {
const App({super.key});
#override
State<StatefulWidget> createState() => _AppState();
}
class _AppState extends State<App> {
ScreenState ss = ScreenState.register;
#override
Widget build(BuildContext context) {
switch (ss) {
case ScreenState.register:
return registerPage();
default:
return registerPage();
}
}
}
screens.dart
import 'package:flutter/material.dart';
import 'components.dart';
Widget registerPage() {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.blueGrey,
),
home: Scaffold(
appBar: appHeader(),
body: registerForm(),
),
);
}
components.dart
import 'package:flutter/material.dart';
PreferredSizeWidget appHeader() {
return AppBar(
title: const Text('Register Form'),
actions: [
TextButton(
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
'Home',
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline,
),
),
),
onPressed: () {/* _AppState.ss = ScreenState.home; */},
),
TextButton(
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
'Log In',
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline,
),
),
),
onPressed: () {/* _AppState.ss = ScreenState.login; */},
),
],
);
}
Widget registerForm() {
return SingleChildScrollView(
child: Center(
child: Container(
constraints: const BoxConstraints(
minWidth: 300,
maxWidth: 500,
),
padding: const EdgeInsets.symmetric(
vertical: 40,
horizontal: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text('Account Information'),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Create username',
hintText: 'Enter username',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please create a username' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Create password',
hintText: 'Enter password',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please create a password' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
labelText: 'Re-enter password',
hintText: 'Enter password',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please re-enter password' : null;
},
),
const SizedBox(
height: 30,
),
const Text('Personal information'),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Last name',
hintText: 'Enter your last name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please enter your last name' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'First name',
hintText: 'Enter your first name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
validator: (value) {
return value!.isEmpty ? 'Please enter your first name' : null;
},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Middle name (optional)',
hintText: 'Enter your middle name',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
),
const SizedBox(
height: 10,
),
TextFormField(
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: 'Suffix (optional)',
hintText: 'Enter your suffix',
prefixIcon: Icon(Icons.edit),
border: OutlineInputBorder(),
),
onChanged: (String value) {},
),
],
),
),
),
);
}
I commented out the code that I expect to work but it turns out to be an error. Please teach me on how to fix the error. Thank you so much.
You can change your state to this:
class _AppState extends State<App> {
ScreenState ss = ScreenState.register;
#override
Widget build(BuildContext context) {
switch (ss) {
case ScreenState.register:
return registerPage(changeState);
default:
return registerPage(changeState);
}
}
void changeState(ScreenState s) {
setState(() {
ss = s;
});
}
}
Then registerPage like
Widget registerPage(Function(ScreenState) f) {
with
appBar: appHeader(f),
and then appHeader like
PreferredSizeWidget appHeader(Function(ScreenState) f) {
and then this for example:
onPressed: () {f(ScreenState.home);},

Conditional statement for DropdownButtonFormFields in registeration form

Still a newbie with flutter and was wondering if someone could help me with a problem I'm having. I am trying to create a registeration form with email, password, password confirmation, a county and a zip code. (County and zip code forms are the drop down button form fields) I have successfully coded all else except for the zip code drop down. I would need it to be conditional on the county selection. (In a way that if I select a specific county in cali, it would only display that selected county's zip codes and nothing else). Also if someone would know a quick fix to make the dropdown button form fields empty unless clicked on. My current adaptation on it isn't very functional, since you can just leave the option unanswered, when it's supposed to be mandatory. Thank you in advance :)
Existing code below
(I only have the string for one county zip codes) (Also deleted the irrelevant firebase related code for this post)
class RegisterPage extends StatefulWidget {
const RegisterPage({Key? key}) : super(key: key);
#override
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
// dropdown area
_MyFormStateArea(){
selectedArea = dropdownListArea[0];
}
var selectedArea = '';
final dropdownListArea = <String>['', 'LA', 'San Francisco'...'Santa Barbara'];
// dropdown zipcode
_MyFormStateZip(){
selectedZip = dropdownListZip[0];
}
var selectedZip = '';
final dropdownListZip = <String>['', '90001', '90002', '90003',..., '91609'];
// editing Controller
final emailEditingController = new TextEditingController();
final passwordEditingController = new TextEditingController();
final confirmPasswordEditingController = new TextEditingController();
#override
Widget build(BuildContext context) {
// email field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty) {
return ("Please enter email.");
}
// reg expression for email validation
if (!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]")
.hasMatch(value)) {
return ("Please enter a working email.");
}
return null;
},
onSaved: (value) {
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// password field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value) {
RegExp regex = new RegExp(r'^.{6,}$');
if (value!.isEmpty) {
return ("A password required.");
}
if(!regex.hasMatch(value)) {
return ("Please enter other password (Min. 6 characters)");
}
},
onSaved: (value) {
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
));
// confirm password field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if(confirmPasswordEditingController.text != passwordEditingController.text)
{
return "Passwords don't match";
}
return null;
},
onSaved: (value) {
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password again",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
);
// area dropdown
final areaField = DropdownButtonFormField(
value: selectedArea,
items: dropdownListArea.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: dropdownListZip.map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// sign up button
final signUpButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.white,
child: MaterialButton(
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: Text("Sign Up", textAlign: TextAlign.center,
style: TextStyle(fontSize: 20,
color: Colors.lightBlue[900],
fontWeight: FontWeight.bold)
),
),
);
return Scaffold(
backgroundColor: Color(0xFFAED8E6),
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => FrontPage()));
},
icon: Icon(Icons.arrow_back),
color: Colors.lightBlue[900],
),
),
body: Center(
child: SingleChildScrollView(
child: Container(
color: Color(0xFFAED8E6),
child: Padding(
padding: const EdgeInsets.fromLTRB(36, 20, 36, 30),
child: Form(
key: _formKey,
child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 170,
child: Image.asset("assets/AR_logoBold.png",
fit: BoxFit.contain
)),
SizedBox(height: 40,),
emailField,
SizedBox(height: 25,),
passwordField,
SizedBox(height: 25,),
confirmPasswordField,
SizedBox(height: 25,),
areaField,
SizedBox(height: 25,),
zipCodeField,
SizedBox(height: 35,),
signUpButton,
SizedBox(height: 15,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("You already own an account? "),
GestureDetector(onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child: Text("Login",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Colors.lightBlue[900])
),)
],
)
],
)),
),
),
),
),
);
}
}
First you should initalize the selectedArea and selectedZip with the first Entry of your List: = dropdownListZip.first and the first entry should not be an empty String
To get only zips that belong to the choosen area you need to know them. At the moment you have two independent lists.
Better you use a map like:
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
Than you can only display zips that belong to the area quite easy.
Take a look at: Flutter Documentation for Map
Map<String, List<String>> zipmap = Map('LA': ['9000','9001','9002], 'San Francisco': ['9003', '9004']);
final areaField = DropdownButtonFormField(
value: selectedArea,
items: zipmap.keys.toList().map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedArea = value;
}
});
},
decoration: InputDecoration(
labelText: 'County',
prefixIcon: Icon(Icons.location_city_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);
// zip code field
final zipCodeField = DropdownButtonFormField(
value: selectedZip,
items: zipmap[selectedArea].map((e) =>
DropdownMenuItem(value: e, child: Text(e),)).toList(),
onChanged: (String? value) {
setState(() {
if (value != null) {
selectedZip = value;
}
});
},
decoration: InputDecoration(
labelText: 'Zip Code',
prefixIcon: Icon(Icons.location_on_outlined),
contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
)
);

Exception caught by gesture 'then' was called on null

I faced this error when I tried to insert image
"The following NoSuchMethodError was thrown while handling a gesture:
The method 'then' was called on null.
Receiver: null
Tried calling: then(Closure: (dynamic) => Null)"
Below is my code. Hope someone can help me with it. I have no idea how to solve it. Thank you.
// ignore_for_file: import_of_legacy_library_into_null_safe, unrelated_type_equality_checks
import 'dart:io';
import 'package:dparking/model/user_model.dart';
import 'package:dparking/screens/home_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_picker/image_picker.dart';
class RegistrationScreen extends StatefulWidget {
const RegistrationScreen({Key? key}) : super(key: key);
#override
State<RegistrationScreen> createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
final _auth = FirebaseAuth.instance;
// form key
final _formKey = GlobalKey<FormState>();
// editing Controller
final nameEditingController = TextEditingController();
final emailEditingController = TextEditingController();
final passwordEditingController = TextEditingController();
final confirmPasswordEditingController = TextEditingController();
final phoneNumberEditingController = TextEditingController();
XFile? _logo;
final ImagePicker _picker = ImagePicker();
#override
Widget build(BuildContext context) {
// Name field
final nameField = TextFormField(
autofocus: false,
controller: nameEditingController,
keyboardType: TextInputType.emailAddress,
validator: (value) {
RegExp regex = RegExp(r'^.{3,}$');
if(value!.isEmpty){
return ("Name cannot be Empty");
}
if(!regex.hasMatch(value))
{
return ("Enter Valid Name(Min. 3 Character");
}
return null;
},
onSaved: (value)
{
nameEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.account_circle),
contentPadding: const EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Name",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
// Email field
final emailField = TextFormField(
autofocus: false,
controller: emailEditingController,
keyboardType: TextInputType.emailAddress,
validator: (value)
{
if(value!.isEmpty)
{
return ("Please Enter Your Email");
}
// reg expression for email validation
if(!RegExp("^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]").hasMatch(value))
{
return("Please Enter a valid email");
}
return null;
},
onSaved: (value)
{
emailEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.mail),
contentPadding: const EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
// Password field
final passwordField = TextFormField(
autofocus: false,
controller: passwordEditingController,
obscureText: true,
validator: (value) {
RegExp regex = RegExp(r'^.{6,}$');
if(value!.isEmpty){
return ("Password is required for login");
}
if(!regex.hasMatch(value))
{
return ("Enter Valid Password(Min. 6 Character");
}
return null;
},
onSaved: (value)
{
passwordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.vpn_key),
contentPadding: const EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
// Confirm Password field
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordEditingController,
obscureText: true,
validator: (value)
{
if(confirmPasswordEditingController.text.length !=
passwordEditingController.text){
return "Password Does Not Match";
}
return null;
},
onSaved: (value)
{
confirmPasswordEditingController.text = value!;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.vpn_key),
contentPadding: const EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Confirm Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
//signup button
final signupButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(30),
color: Colors.redAccent,
child: MaterialButton(
padding: const EdgeInsets.fromLTRB(20, 15, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
signUp(emailEditingController.text, passwordEditingController.text);
},
child: const Text("SignUp", textAlign: TextAlign.center,
style: TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold,),
),
),
);
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.red),
onPressed: (){
Navigator.of(context).pop();
},
),
),
body: Center(
child: SingleChildScrollView(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 200,
width: 300,
child: Image.asset("assets/images/DParking.png",
fit: BoxFit.contain,
color: Colors.black,
),
),
nameField,
const SizedBox(height: 30),
emailField,
const SizedBox(height: 30),
passwordField,
const SizedBox(height: 30),
confirmPasswordField,
const SizedBox(height: 30),
InkWell(
onTap: (){
_pickImage().then((value){ //i think the error is here
setState((){
_logo = value;
});
});
},
child: Card(
elevation: 4,
child: _logo==null ? const SizedBox(
height: 100,
width: 250,
child: Center(
child: Text('Insert Identification Card'),
),
):SizedBox(
height: 100,
width: 250,
child: Image.file(File(_logo!.path),)
),
),
),
const SizedBox(height: 30),
signupButton,
const SizedBox(height: 30),
],
),
),
),
),
),
)
);
}
void signUp(String email, String password) async
{
if (_formKey.currentState!.validate()) {
await _auth
.createUserWithEmailAndPassword(email: email, password: password)
.then((value) => {postDetailsToFirestore()})
.catchError((e) {
Fluttertoast.showToast(msg: e!.message);
});
}
}
postDetailsToFirestore() async {
// call firestore
//call user model
//send value
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = _auth.currentUser;
UserModel userModel = UserModel();
userModel.email = user!.email;
userModel.uid = user.uid;
userModel.name = nameEditingController.text;
await firebaseFirestore
.collection("users")
.doc(user.uid)
.set(userModel.toMap());
Fluttertoast.showToast(msg: "Account created successfully");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => const HomeScreen()),
(route) => false);
}
}
_pickImage() {
}

I created a login page and I need to add these things to my username. how i validate my form in flutter

Minimum 1 alphabetic
Minimum 1 number
Allow only Character (_)
its failed
Pattern pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[_]).{8,}$';
RegExp regex = new RegExp(pattern);
Just check out this example that i have created :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TextEditingController userName = TextEditingController();
FocusNode usernameFocus = new FocusNode();
String errorText;
bool _isValid = false;
#override
void initState() {
super.initState();
userName.addListener(() {
String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[_]).{8,}$';
RegExp regExp = new RegExp(pattern);
if (userName.text.isEmpty) {
setState(() {
errorText = 'Field cannot be empty';
});
} else {
if (!regExp.hasMatch(userName.text)) {
print('The does not matches the requirement');
setState(() {
// here you can add you text
errorText =
'Minimum 1 Capital letter, 1 small letter and 1 number and _';
_isValid = false;
});
} else {
print('the value matches');
setState(() {
errorText = null;
_isValid = true;
});
}
}
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: TextField(
focusNode: usernameFocus,
decoration: new InputDecoration(
errorText: errorText,
prefixIcon: Icon(
Icons.supervised_user_circle,
color: Color(0xFF282858),
),
labelText: "UserName",
labelStyle: TextStyle(
fontFamily: "Poppins-Medium",
color: usernameFocus.hasFocus
? Colors.grey[600]
: Colors.grey[600]),
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[400], width: 2.0),
borderRadius: BorderRadius.circular(10.0),
),
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(10.0),
borderSide:
new BorderSide(color: Colors.grey[400], width: 2.0),
),
//fillColor: Colors.green
),
controller: userName,
keyboardType: TextInputType.text,
),
),
RaisedButton(
child: Text('Login'),
onPressed: () {
print(_isValid);
if (!_isValid) {
return;
}
print('validation sucess');
},
)
],
)),
),
);
}
}
let me know if it works.
You would need to use a validator on your Textfield. You would add a condtion in the validator function to check if it's false and returns the error meessage that you would like the user to see.
You can either validate by using autovalidate: true, or you can do it manualy by using .currentState.validate() on your form before saving.
so your code could look something like this
validator: (value) {
final alphanumeric = RegExp(YOUR_REGEX_HERE);
if (!alphanumeric.hasMatch(value)) return 'YOUR_ERROR_MESSAGE';
}
You can use this library
pubspec.yaml
flutter_form_builder: ^3.7.3
Code will be like this:
GlobalKey _addextKey = GlobalKey();
FormBuilder(
key: _addextKey,
child: ListView(
children: <Widget>[
TextFormField(
textInputAction: TextInputAction.next,
style: textStyle,
controller: _NameauthController,
// ignore: missing_return
validator: FormBuilderValidators.required(),
decoration: InputDecoration(
hintText: 'name',
hintStyle: TextStyle(fontSize: 12.0),
labelStyle: textStyle,
errorStyle:
TextStyle(color: Colors.red, fontSize: 12.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0))),
keyboardType: TextInputType.text,
),
]);),